145 lines
5.1 KiB
Python
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()
|