0
$\begingroup$

Blender 3.4 Windows 10

How do you get all world space coordinates of all the vertices of a mesh? I have created a simple cube, applied a subdivision surface modifier, and added wave animation using a wave deformer. The code below is giving data of only 8 vertices of the cube. It's not considering subdivision modifiers and I'm not sure about wave deformation data.

obj = bpy.context.selected_objects[0]
# Vertex coordinates
coords = [(obj.matrix_world @ v.co) for v in obj.data.vertices]
# 1d array of vertices
vertices = np.array(coords, dtype=ctypes.c_double).flatten()
print(vertices)

I need a flattened array of vertex coordinates and the above approach is costly in terms of 2 steps to get the data. Is it the correct way?

I have saved per frame vertex coordinates of an animated mesh externally to a cache file. Now I would like to apply this data back to mesh on per frame basis. This is my logical script:

for f in range(buffer.start_frame, buffer.end_frame):
  # Move to frame
  bpy.context.scene.frame_set(f)
  for mesh in buffer[f]:
    # Get mesh from blender scene using name
    blender_mesh = get_mesh(mesh.name)
    # Apply vertex data from buffer to blender mesh. 
    blender_mesh.set_vertices(mesh.vertices)
    # Update blender mesh by recalculating normals which I believe
    # is required as I have updated vertex positions.
    blender_mesh.recalculate_normals()
    # Anoter option is to write normals also in buffer and apply
    # to blender mesh easily as vertices.
    blender_mesh.set_normals(mesh.normals)

I would really apperciate if some one can change this logical script into practical one. In case I have to recalculate normals, this is the way I have found it's done which I'm not sure is the correct way.

def recalculate_normals(mesh):
    """ Make normals consistent for mesh """
    bm = bmesh.new()
    bm.from_mesh(mesh)
    bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
    bm.to_mesh(mesh)
    bm.free()
$\endgroup$

1 Answer 1

0
$\begingroup$

I think a good solution to your problem is using Shape Keys. They will modify based the mesh based on the key, which stores a mesh data.

Using Shape Keys I achieved the following result(Project: Game of Life inside Blender): enter image description here

based on shape keys the set_vertices could look something like this: I take the vertices as a list of list e.g., [[1.1, 0, 0], [5, 7, 8], ...] Since you don't have saved any face (and edge) data for the vertices. The mesh will be some unconnected points.

def set_vertices(obj: bpy.types.Object, mesh: bpy.types.Mesh, vertices: list):
    # add missing geometry
    missing_vertices = len(vertices) - len(mesh.vertices)
    if missing_vertices > 0:
        mesh.vertices.add(missing_vertices)
        
    frame = bpy.context.scene.frame_current
    shape_key = obj.shape_key_add(f"Frame {frame}", from_mix= False)
    shape_key.interpolation = 'KEY_LINEAR'
    #apply to shape key
    for vert, coord in zip(shape_key.data, vertices):
        vert.co = coord
    # insert to keyframe
    shape_keys = obj.data.shape_keys
    shape_keys.use_relative = False
    shape_keys.eval_time = shape_key.frame
    shape_keys.keyframe_insert('eval_time', frame= frame, group= obj.name)

Implementation without shape keys:

def set_vertices(mesh: bpy.types.Mesh, vertices: list):
    mesh.clear_geometry()
    mesh.from_pydata(vertices, [], [])

I don't know how you want to implement normal recalculation if you don't have any faces. (maybe the faces don't change?)

$\endgroup$

You must log in to answer this question.

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