2

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.

dermit
  • 23
  • 3
  • What is the difference between your function and New Shape From Mix? – Crantisz Aug 11 '21 at 12:43
  • 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: https://blender.stackexchange.com/questions/5364/how-to-apply-shape-keys/5365#5365 and I will see if I find a way to use that without deleting all my shape keys – dermit Aug 11 '21 at 13:06
  • Big question mark re why toggle into edit mode in question code? Feel that bmesh.from_object in OBJECT mode is the go here. – batFINGER Aug 11 '21 at 13:29
  • That is my bad, it was a desperate change, changed back to the correct Object mode. – dermit Aug 11 '21 at 13:31

2 Answers2

1

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.

batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • Thanks a lot, both of those work for my application, also thanks for the optimization, poi is indeed a list of indices – dermit Aug 15 '21 at 14:07
  • Thankyou, appreciated. See https://blender.stackexchange.com/a/233823/15543 verts[poi] – batFINGER Aug 15 '21 at 14:15
0

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

dermit
  • 23
  • 3