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 '21 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 '21 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 '21 at 13:29
  • $\begingroup$ That is my bad, it was a desperate change, changed back to the correct Object mode. $\endgroup$
    – dermit
    Aug 11 '21 at 13:31
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 '21 at 14:07
  • $\begingroup$ Thankyou, appreciated. See blender.stackexchange.com/a/233823/15543 verts[poi] $\endgroup$
    – batFINGER
    Aug 15 '21 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$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.