Files
workinf_Blender_Wasm/tools/web/generate-modifier-goldens.py
2026-08-12 04:47:48 -04:00

145 lines
5.1 KiB
Python

import json
import os
import sys
import bpy
FIXTURES = [
"modifier_generate_scene.blend",
"modifier_deform_scene.blend",
"modifier_deform_curve_scene.blend",
"modifier_physics_scene.blend",
"modifier_geometry_nodes_scene.blend",
"modifier_grease_pencil_scene.blend",
]
def modifier_type_code(modifier):
items = bpy.types.Modifier.bl_rna.properties["type"].enum_items
item = items.get(modifier.type)
return item.value if item is not None else -1
def modifier_record(modifier):
record = {
"name": modifier.name,
"type": modifier.type,
"typeCode": modifier_type_code(modifier),
"showViewport": modifier.show_viewport,
"showRender": modifier.show_render,
"showEditmode": modifier.show_in_editmode,
"showOnCage": modifier.show_on_cage,
}
targets = []
for field in ("object", "target", "auxiliary_target"):
if hasattr(modifier, field):
target = getattr(modifier, field)
if target is not None and target.name not in targets:
targets.append(target.name)
if targets:
record["targetObjects"] = targets
if modifier.type == "NODES" and modifier.node_group is not None:
record["nodeGroup"] = modifier.node_group.name
return record
def evaluated_mesh_record(obj, depsgraph):
evaluated = obj.evaluated_get(depsgraph)
mesh = evaluated.to_mesh(preserve_all_data_layers=True, depsgraph=depsgraph)
try:
mesh.calc_loop_triangles()
return {
"object": obj.name,
"sourceMesh": obj.data.name,
"vertexCount": len(mesh.vertices),
"triangleCount": len(mesh.loop_triangles),
"positions": [component for vertex in mesh.vertices for component in vertex.co],
"indices": [index for triangle in mesh.loop_triangles for index in triangle.vertices],
"worldMatrix": [value for row in evaluated.matrix_world for value in row],
}
finally:
evaluated.to_mesh_clear()
def grease_pencil_record(obj):
layers = []
for layer in obj.data.layers:
frames = []
for frame in layer.frames:
drawing = frame.drawing
frames.append({
"frame": frame.frame_number,
"strokeCount": len(drawing.strokes),
"pointCount": sum(len(stroke.points) for stroke in drawing.strokes),
"positions": [component for stroke in drawing.strokes for point in stroke.points
for component in point.position],
})
layers.append({"name": layer.name, "frames": frames})
return {"object": obj.name, "data": obj.data.name, "layers": layers}
def node_group_records():
return [{
"name": group.name,
"type": group.bl_idname,
"nodes": [{"name": node.name, "type": node.bl_idname} for node in group.nodes],
"links": len(group.links),
} for group in bpy.data.node_groups]
def golden_for_fixture(path):
bpy.ops.wm.open_mainfile(filepath=path)
scene = bpy.context.scene
scene.frame_set(scene.frame_current)
depsgraph = bpy.context.evaluated_depsgraph_get()
objects = []
meshes = []
grease_pencils = []
for obj in sorted(bpy.data.objects, key=lambda item: item.name):
objects.append({
"name": obj.name,
"type": obj.type,
"modifiers": [modifier_record(modifier) for modifier in obj.modifiers],
})
if obj.type == "MESH":
meshes.append(evaluated_mesh_record(obj, depsgraph))
elif obj.type == "GREASEPENCIL":
grease_pencils.append(grease_pencil_record(obj))
return {
"schemaVersion": 1,
"blenderVersion": bpy.app.version_string,
"fixture": os.path.basename(path),
"frame": scene.frame_current,
"objects": objects,
"meshes": meshes,
"nodeGroups": node_group_records(),
"greasePencils": grease_pencils,
"tolerance": {"maxPositionError": 1e-5, "rmsPositionError": 1e-6},
}
def main():
if "--" not in sys.argv or len(sys.argv[sys.argv.index("--") + 1:]) < 2:
raise SystemExit("usage: blender -b --python generate-modifier-goldens.py -- fixture-directory output-directory")
args = sys.argv[sys.argv.index("--") + 1:]
fixture_directory, output_directory = args[:2]
fixture_directory = os.path.abspath(fixture_directory)
output_directory = os.path.abspath(output_directory)
os.makedirs(output_directory, exist_ok=True)
requested = args[2:] or FIXTURES
for fixture in requested:
if fixture not in FIXTURES:
raise SystemExit(f"unknown modifier fixture: {fixture}")
source = os.path.join(fixture_directory, fixture)
golden = golden_for_fixture(source)
output = os.path.join(output_directory, fixture.replace(".blend", ".json"))
with open(output, "w", encoding="utf-8") as handle:
json.dump(golden, handle, indent=2, sort_keys=True)
handle.write("\n")
print(f"modifier-golden-generated fixture={fixture} output={output}")
if __name__ == "__main__":
main()