I am working on a python module that does off screne rendering for cloth simulation. Right now I'm using the build in cloth simulation in the physics tab to model the cloth fall and drape. I'm trying to create a generic tool that can simulate any fabric over any object so I want to parameratize the simulation.
Currently, I'm trying to get the simulation to run until the cloth has reached a 'steady state', (temporal changes are below some threshold). I don't want to hard code a stop frame for the simulation as for simple setups this will overprocess, and for complex ones it may not fully capture the main evolution.
My thought was to compare the mesh at the current frame with the mesh from the previous frame and calculate a mean difference between verticies positions. This should give me an approximate difference between the two mesh, and once this delta is below a threshold, I will stop the simulation.
I have a function to calculate the difference between 2 mesh, and I'm happy with that, but I can't figure out how to put it inside a loop that advances the simulation. My mesh comparison on below.
def delta_mesh(bmesh1, bmesh2):
#code required in bmesh to ensure enumeration of verts works
#https://blender.stackexchange.com/questions/31738/how-to-fix-outdated-internal-index-table-in-an-addon
if hasattr(bmesh1.verts, "ensure_lookup_table"):
bmesh1.verts.ensure_lookup_table()
if hasattr(bmesh2.verts, "ensure_lookup_table"):
bmesh2.verts.ensure_lookup_table()
############################################################
size1 = len(bmesh1.verts)
size2 = len(bmesh2.verts)
delta = np.zeros(size1)
if size1 == size2:
for ii in range(len(bmesh1.verts)):
delta[ii] = np.linalg.norm(bmesh1.verts[ii].co - bmesh2.verts[ii].co)
delta = np.mean(delta)
else:
delta = -1
return delta
I'm currently trying to just test this by putting the delta calculation inside a fixed loop and outputting the evolution. :
obj = bpy.data.objects['cloth']
obj.select_set(True)
view_layer.objects.active = obj
#create initial 'old' mesh'
bpy.ops.object.mode_set(mode = "EDIT")
me = obj.data
bm_old = bmesh.from_edit_mesh(me)
for frame in range(stop_frame):
bpy.context.scene.frame_set(frame)
obj = bpy.data.objects['cloth']
bpy.ops.object.mode_set(mode = "EDIT")
me = obj.data
bm = bmesh.from_edit_mesh(me)
diff = delta_mesh(bm, bm_old)
print("bm.vert[0].co:", bm.verts[0].co, "bm_old.vert[0].co:", bm_old.verts[0].co)
print("frame:",frame," diff:",diff)
bm_old = bm.copy()
bpy.ops.object.mode_set(mode = "OBJECT")
This currently runs, but neither mesh evolves as the simulation run. I'm pretty sure the problem is that the object is in 'Edit' mode and this is interfering with the physics simulation, but if I try to put it back into 'Object' mode at the end of every loop, the bmesh object gets destroyed, so the 'bm_old' is lost.
I think I need to create a copy of the mesh that isn't associated with the original objects, but I don't want to be creating whole new objects every frame just to delete them again. Is there a way to 'de-link' the bmesh from an object and save it as a new entity?
Or am I going about this in the complete wrong way?