"""Import a browser-produced OBJ in pinned Blender 5.2 and emit a semantic report.""" import hashlib import json import sys from pathlib import Path import bpy def sha256_file(path): digest = hashlib.sha256() with open(path, "rb") as handle: for chunk in iter(lambda: handle.read(1024 * 1024), b""): digest.update(chunk) return digest.hexdigest() def report_scene(): objects = [] for obj in sorted((item for item in bpy.context.scene.objects if item.type == "MESH"), key=lambda item: item.name): mesh = obj.data mesh.calc_loop_triangles() uv_layers = sorted(layer.name for layer in mesh.uv_layers) objects.append({ "name": obj.name, "vertexCount": len(mesh.vertices), "polygonCount": len(mesh.polygons), "triangleCount": len(mesh.loop_triangles), "normalCount": len(mesh.vertices), "uvLayers": uv_layers, "uvLoopCount": len(mesh.uv_layers.active.data) if mesh.uv_layers.active else 0, "materials": sorted(material.name for material in mesh.materials if material), }) return {"objects": objects, "objectCount": len(objects), "meshCount": len(objects)} def main(obj_path, report_path): obj_path = Path(obj_path).resolve() report_path = Path(report_path).resolve() bpy.ops.wm.read_factory_settings(use_empty=True) result = bpy.ops.wm.obj_import( filepath=str(obj_path), directory=str(obj_path.parent), forward_axis="NEGATIVE_Z", up_axis="Y", global_scale=1.0, use_split_objects=True, use_split_groups=True, validate_meshes=True, import_vertex_groups=False, ) if "FINISHED" not in result: raise RuntimeError("Blender OBJ import did not finish: %s" % (result,)) report = { "schemaVersion": 1, "operation": "DESKTOP_IMPORT_WEB_OBJ", "sourceObjSha256": sha256_file(obj_path), "sourceObjBytes": obj_path.stat().st_size, **report_scene(), } report_path.parent.mkdir(parents=True, exist_ok=True) report_path.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8") print("obj-web-roundtrip-desktop-imported objects=%s triangles=%s" % (report["objectCount"], sum(item["triangleCount"] for item in report["objects"]))) if __name__ == "__main__": args = sys.argv[sys.argv.index("--") + 1 :] if "--" in sys.argv else [] if len(args) != 2: raise SystemExit("usage: blender --background --python check-obj-web-roundtrip.py -- OBJ REPORT") main(args[0], args[1])