I want to create an animation where I extract vertex coordinates, store them, and reanimate the object without physics using the stored coordinate data. I'm currently capturing vertex coordinates for each frame and saving them to a file:
def get_vertices_info(obj_name):
obj = bpy.data.objects[obj_name]
obj_data = obj.data
vertices_data = {}
for vertex_index, vertex in enumerate(obj_data.vertices):
vertex_data = []
for frame in range(bpy.context.scene.frame_start, bpy.context.scene.frame_end + 1):
bpy.context.scene.frame_set(frame)
vertex_world_co = obj.matrix_world @ vertex.co
frame_data = tuple(vertex_world_co)
vertex_data.append(frame_data)
vertices_data[f"Vertex {vertex_index + 1}"] = vertex_data
return vertices_data
#(wind_strength, wind_directions, wind_coordinates) = get_wind_info("Wind")
vertices_data = get_vertices_info("Plane")
data = {
"wind": {
"strength": wind_strength,
"directions": wind_directions,
"coordinates": wind_coordinates
},
"verticies": vertices_data
}
And then animate on another scene:
new_scene = bpy.data.scenes.new("Animated Scene")
original_obj = bpy.data.objects['Plane']
flag = original_obj.copy()
flag.data = original_obj.data.copy()
flag.modifiers.remove(flag.modifiers.get("Cloth"))
new_scene.collection.objects.link(flag)
bpy.context.window.scene = new_scene
vertex_data = list(data["meshes"].values())
# https://blender.stackexchange.com/questions/36902/how-to-keyframe-mesh-vertices-in-python
def insert_keyframe(fcurves, frame, values):
for fcu, val in zip(fcurves, values):
fcu.keyframe_points.insert(frame, val, options={'FAST'})
obj = bpy.context.active_object
mesh = flag.data
action = bpy.data.actions.new("MeshAnimation")
mesh.animation_data_create()
mesh.animation_data.action = action
data_path = "vertices[%d].co"
values = vertex_data
frames = list(range(0,len(values[0]) + 1))
for i,v in enumerate(mesh.vertices):
fcurves = [action.fcurves.new(data_path % v.index, index = i) for i in range(3)]
co_rest = v.co
for t, value in zip(frames, values[i]):
insert_keyframe(fcurves, t, value)
If I collect data from an object without a cloth modifier, it partially works.(probably i messed up with the coordinates directions). However, when the object has a cloth modifier applied, plane remaining stationary.
Scene collected data from. Applied rigid body:
Animated scene using collected data:
Here's the scenario where I want to collect data (with a cloth modifier applied):
However, when I animate with this data, nothing occurs; the plane remains static.
I tried couple of different functions as I suspect the issue lies in data collection. Here is the collected data with rigid body:
"verticies": {
"Vertex 1": [
[
0.0683371052145958,
-1.5310348272323608,
0.931662917137146
],
[
0.5171984434127808,
-1.5432056188583374,
0.40158990025520325
],
...
Here is with cloth:
"verticies": {
"Vertex 1": [
[
0.0683371052145958,
-1.5310348272323608,
0.931662917137146
],
[
0.0683371052145958,
-1.5310348272323608,
0.931662917137146
],
As you can see, with rigid body, vertex position changes over time but with cloth it remains static.
I figure it out! Thanks to this question for introducing me to bmesh
Here is the revisited save function:
def get_vertices_frame_by_frame(end_frame):
data = {}
flag_obj = bpy.data.objects.get("Flag")
for frame in range(1,end_frame + 1):
bpy.context.scene.frame_current = frame
dg = bpy.context.evaluated_depsgraph_get()
bm = bmesh.new()
bm.from_object(flag_obj, dg)
vert_tuples = tuple((vert.co.x, vert.co.y, vert.co.z) for vert in bm.verts)
data[f"Frame-{frame}"] = vert_tuples
bm.free()
return data
vertices_data = get_vertices_by_frame(30)
data = {
"vertices" : vertices_data
}
And load function:
vertex_data_by_frame = data["vertices"].values()
for frame_num, vertices in enumerate(vertex_data_by_frame):
for i, v in enumerate(vertices):
vertex = flag.data.vertices[i]
vertex.co = v
vertex.keyframe_insert(data_path="co", frame=frame_num + 1)