2
$\begingroup$

I'm trying to write a function that returns vertex coordinates including their transformation that was a applied by (one or multiple) shape keys. Currently this is how I tried, but I only get vertex coordinates before the shape keys are applied:

def get_vertex_coords():
    ob = bpy.data.objects['cc_base_body']
    curmode = bpy.context.object.mode
    bpy.ops.object.mode_set(mode='OBJECT')
    mesh = ob.to_mesh(preserve_all_data_layers=True, depsgraph = bpy.context.evaluated_depsgraph_get())
    bm = bmesh.new()
    bm.from_mesh(mesh)
    coords = []
    for vertex in bm.verts:
        if vertex.index in poi:
            coords.append(vertex.co) # ob.matrix_world @ 
    bpy.ops.object.mode_set(mode=curmode)
    return coords

Is there any way to do this?

Thanks to the comments I found a way, see my posted answer.

$\endgroup$
4
  • $\begingroup$ What is the difference between your function and New Shape From Mix? $\endgroup$
    – Crantisz
    Aug 11, 2021 at 12:43
  • $\begingroup$ I'm not sure I know exactly what new shape from mix does. My function is supposed to give me the world coordinates of vertices (filtered with the poi list). New shape from mix adds a new shape key I think. Would that lead to the vertex coordinates being adjusted (in a way accessible to me?) Edit: I just saw this answer: blender.stackexchange.com/questions/5364/… and I will see if I find a way to use that without deleting all my shape keys $\endgroup$
    – dermit
    Aug 11, 2021 at 13:06
  • $\begingroup$ Big question mark re why toggle into edit mode in question code? Feel that bmesh.from_object in OBJECT mode is the go here. $\endgroup$
    – batFINGER
    Aug 11, 2021 at 13:29
  • $\begingroup$ That is my bad, it was a desperate change, changed back to the correct Object mode. $\endgroup$
    – dermit
    Aug 11, 2021 at 13:31

2 Answers 2

1
$\begingroup$

Bmesh.from_object

Would use this method for the modified / deformed coordinates

How do I get a mesh data-block with modifiers and shape keys applied in Blender 2.8? since we are going to load up a bmesh.

enter image description here

Modified and deformed cube shown in edit mode. Test script below, create a modified and deform applied mesh copy, or with cage = True the deformed cage mesh as shown in edit mode above, with modifiers intact.

Instead of printing result, returned mesh as a result and made object copies to visualize result.

import bpy
import bmesh
from bpy import context

def get_modified_mesh(ob, cage=False):
    bm = bmesh.new()
    bm.from_object(
            ob,
            context.evaluated_depsgraph_get(),
            cage=cage,
            )

    #bm.transform(ob.matrix_world)
    me = bpy.data.meshes.new("Deformed")
    bm.to_mesh(me)
    return me


context.object.update_from_editmode()
# make a modified and deformed copy
ob = context.object.copy()
me = get_modified_mesh(ob)
ob.modifiers.clear()
ob.data = me
context.collection.objects.link(ob)

# make a deformed copy (keep modifiers)
ob = context.object.copy()
me = get_modified_mesh(ob, cage=True)
ob.data = me
context.collection.objects.link(ob)

Note, if poi is a list of indices then

bm.verts.ensure_lookup_table()
coords = [bm.verts[i].co for i in poi]

looping over all and testing for inclusion is very unoptimal.

$\endgroup$
2
  • $\begingroup$ Thanks a lot, both of those work for my application, also thanks for the optimization, poi is indeed a list of indices $\endgroup$
    – dermit
    Aug 15, 2021 at 14:07
  • $\begingroup$ Thankyou, appreciated. See blender.stackexchange.com/a/233823/15543 verts[poi] $\endgroup$
    – batFINGER
    Aug 15, 2021 at 14:15
0
$\begingroup$

Edit: Thanks to Crantisz and this answer How to apply shape keys? I found a way:

I duplicate the object whose vertices I'm looking at, add a new shape key to the duplicated object:

ob.shape_key_add(name="temp", from_mix=True)

and then delete all shape keys from the duplicated object:

for key in ob.data.shape_keys.key_blocks:
    ob.shape_key_remove()

I can then get the vertex coordinates and delete the new object:

def get_vertex_coords():
    curmode = bpy.context.object.mode
    bpy.ops.object.mode_set(mode='OBJECT')
    #deselected all then select the object we want to copy (using operators since this seems to be the proper way to do it in blender)
    bpy.ops.object.select_all(action='DESELECT')
    bpy.data.objects['cc_base_body.001'].select_set(True) #The mesh name should be a parameter here
    bpy.ops.object.duplicate()     
    ob = bpy.context.active_object # This should now give us the duplicated object
    
    #Add the shape key
    ob.shape_key_add(name="temp", from_mix=True)
    #now remove all shape keys
    for key in ob.data.shape_keys.key_blocks:
        ob.shape_key_remove()    

    
    mesh = ob.to_mesh(preserve_all_data_layers=True, depsgraph = bpy.context.evaluated_depsgraph_get())
    bm = bmesh.new()
    bm.from_mesh(mesh)
    coords = []
    for vertex in bm.verts:
        if vertex.index in poi:
            coords.append(vertex.co) # ob.matrix_world @ 
    bpy.ops.object.delete()
    bpy.ops.object.mode_set(mode=curmode)
    
    return coords
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .