I aim to do the following using Blender 2.82a and python: (a) create a mesh in a scene with modifiers and save it, then (b) in another python script, load that same mesh with the same modifiers applied, so that I don't need to re-call the same modifier code [while beyond the scope of this question, I've had trouble with bad physics from this approach].
After an online search, I found documentation for export scene and import scene, along with related StackExchange questions on exporting and importing to .obj files. Here is my minimal working example. I'm using a cloth modifier, but this is not specific to cloth. The TL;DR of the code: (1) clear the scene, (2) create plane and sub-divide it, (3) apply modifiers, (4) save the .obj file. Then, if I run it again with step = 2
in the main method, load the .obj file.
import bpy
import sys
def setup_scene():
for block in bpy.data.meshes:
if block.users == 0:
bpy.data.meshes.remove(block)
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
def make_cloth():
"""Make a plane and sub-divide, then add modifiers."""
bpy.ops.mesh.primitive_plane_add(location=(0, 0, 0))
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.subdivide(number_cuts=20)
bpy.ops.object.editmode_toggle()
# Problem: modifiers are not preserved when saving and loading.
bpy.ops.object.modifier_add(type='CLOTH')
bpy.ops.object.modifier_add(type='SUBSURF')
bpy.ops.object.modifier_add(type='SOLIDIFY')
return bpy.context.object
def save_cloth(cloth, path):
"""Save cloth state (it's the selected object) for loading later."""
bpy.ops.export_scene.obj(filepath=path, use_selection=True, use_mesh_modifiers=True, keep_vertex_order=True)
def load_cloth(path):
"""Load the cloth state from a prior call."""
bpy.ops.import_scene.obj(filepath=path)
cloth = bpy.data.objects['Plane']
print('selected objects: {}'.format(bpy.context.selected_objects))
# We need to re-apply modifiers. But subsurf / solidify will mean bad physics,
# arising from higher vertex counts even with these lines commented out.
#bpy.ops.object.select_all(action='DESELECT')
#bpy.context.view_layer.objects.active = cloth
#cloth.select_set(True)
#bpy.ops.object.modifier_add(type='CLOTH')
#bpy.ops.object.modifier_add(type='SUBSURF')
#bpy.ops.object.modifier_add(type='SOLIDIFY')
return cloth
if __name__ == '__main__':
# First run script with step = 1, then re-run the script again with step = 2:
# blender -P test-save-load-obj.py -- 1
# blender -P test-save-load-obj.py -- 2
argv = sys.argv
argv = argv[argv.index("--") + 1:]
step = int(argv[0])
setup_scene()
path = 'cloth_to_save.obj'
if step == 1:
cloth = make_cloth()
save_cloth(cloth, path)
elif step == 2:
cloth = load_cloth(path)
As mentioned in the comments in the main method, running the above with the step argument as "1" results in the modifiers correctly applied:
The code additionally saves two files: cloth_to_save.mtl
and cloth_to_save.obj
.
I then run blender -P test-save-load-obj.py -- 2
. This will load the meshes. But it will not apply the modifiers:
The above way of saving and loading will correctly preserve the positions of the vertices. So that's good -- I just wonder about the modifiers.
Update 1 (05 June 2020): as batFINGER explains in the comments, use_mesh_modifiers=True
is like clicking on apply in the Blender GUI, and it doesn't involve saving the modifier to the .obj file. Therefore, it's unlikely to be part of my hypothetical solution.
One reason for my confusion is that the documentation for the export method that I'm using:
says that setting use_mesh_modifiers=True
will result in: "Apply Modifiers, Apply modifiers." I'm a little confused about the documentation. My thought after reading it is that the modifiers (such as the cloth, subsurf, and solidify ones I used in my minimum working example) will be applied or preserved in some way. However, since that's not the case with my code, is there something I'm missing? Feel free to also suggest other ways of saving and loading if those are better than my .obj method. For now, I was thinking of just doing the above but explicitly calling the modifiers again (i.e., just repeating the lines of code in make_cloth
that make modifiers).
Related question: this one about exporting to non-Blender programs.
Update 2 (08 June 2020): I modified the script above to take command line arguments. In addition, I further investigated that the vertex count of the cloth will increase dramatically when we load it back in, even without re-applying the cloth or subsurf modifiers. After running blender -P test-save-load-obj.py -- 1
and going to edit mode, I see 484 vertices:
Yet, running blender -P test-save-load-obj.py -- 2
and going to edit mode, I see far more vertices by default even without re-applying modifiers (presumably because subsurf and solidify both increase vertex count implicitly?):
In practice, this results in different physics.
to_mesh
or bmeshfrom_object
to create a mesh with modifiers applied. $\endgroup$to_mesh
orfrom_object
before, I think. I can check those out. $\endgroup$