import json import os import sys import bpy TYPE_NAMES = { "CURVE": "CURVE", "SURFACE": "SURFACE", "FONT": "FONT", "META": "METABALL", } def rounded(value): return round(float(value), 7) def geometry_record(obj, depsgraph): evaluated = obj.evaluated_get(depsgraph) mesh = evaluated.to_mesh() try: mesh.calc_loop_triangles() positions = [component for vertex in mesh.vertices for component in vertex.co] edge_indices = [index for edge in mesh.edges for index in edge.vertices] indices = [index for triangle in mesh.loop_triangles for index in triangle.vertices] point_count = len(mesh.vertices) bounds_min = [min((vertex.co[axis] for vertex in mesh.vertices), default=0.0) for axis in range(3)] bounds_max = [max((vertex.co[axis] for vertex in mesh.vertices), default=0.0) for axis in range(3)] centroid = [ sum((vertex.co[axis] for vertex in mesh.vertices), 0.0) / point_count if point_count else 0.0 for axis in range(3) ] return { "object": obj.name, "sourceType": TYPE_NAMES[obj.type], "vertexCount": point_count, "edgeCount": len(mesh.edges), "triangleCount": len(mesh.loop_triangles), "boundsMin": [rounded(value) for value in bounds_min], "boundsMax": [rounded(value) for value in bounds_max], "centroid": [rounded(value) for value in centroid], "surfaceArea": rounded(sum((triangle.area for triangle in mesh.loop_triangles), 0.0)), "positionMoment": rounded(sum((index + 1) * value for index, value in enumerate(positions))), "edgeIndexMoment": sum((index + 1) * (value + 1) for index, value in enumerate(edge_indices)), "indexMoment": sum((index + 1) * (value + 1) for index, value in enumerate(indices)), } finally: evaluated.to_mesh_clear() def main(output_path): depsgraph = bpy.context.evaluated_depsgraph_get() records = [ geometry_record(obj, depsgraph) for obj in bpy.context.scene.objects if obj.type in TYPE_NAMES ] records.sort(key=lambda record: record["object"]) payload = { "schemaVersion": 1, "blenderVersion": bpy.app.version_string, "fixture": os.path.basename(bpy.data.filepath), "tolerance": { "coordinate": 0.00001, "surfaceArea": 0.0001, "positionMoment": 0.001, }, "geometries": records, } with open(output_path, "w", encoding="ascii") as output: json.dump(payload, output, indent=2, sort_keys=True) output.write("\n") print(f"nonmesh-desktop-golden-generated output={os.path.abspath(output_path)} geometries={len(records)}") if __name__ == "__main__": if "--" not in sys.argv or len(sys.argv) <= sys.argv.index("--") + 1: raise SystemExit("usage: blender -b fixture.blend --python generate-nonmesh-desktop-golden.py -- output.json") main(sys.argv[sys.argv.index("--") + 1])