"""Read-only stage geometry/UV audit and native Blender render.""" import bpy,sys,json from pathlib import Path from mathutils import Vector from mathutils.bvhtree import BVHTree folder=Path(sys.argv[sys.argv.index('--')+1]).resolve() reports=[] for name in ('model.glb','model_lowpoly_uv.glb','model_baked.glb','model_ex.glb'): bpy.ops.wm.read_factory_settings(use_empty=True);bpy.ops.import_scene.gltf(filepath=str(folder/name)) objects=[o for o in bpy.context.scene.objects if o.type=='MESH'] vertices=[o.matrix_world@v.co for o in objects for v in o.data.vertices] minimum=Vector([min(v[i] for v in vertices) for i in range(3)]);maximum=Vector([max(v[i] for v in vertices) for i in range(3)]) reports.append(dict(name=name,minimum=list(minimum),maximum=list(maximum),uvLayers=[[(u.name,len(u.data)) for u in o.data.uv_layers] for o in objects],materials=[s.material.name for o in objects for s in o.material_slots if s.material])) if name not in ('model.glb','model_ex.glb'):continue scene=bpy.context.scene;scene.render.engine='CYCLES';scene.cycles.samples=16;scene.render.resolution_x=640;scene.render.resolution_y=640;scene.render.resolution_percentage=100 world=bpy.data.worlds.new('AuditWorld');world.use_nodes=True;world.node_tree.nodes['Background'].inputs[0].default_value=(.45,.45,.45,1);world.node_tree.nodes['Background'].inputs[1].default_value=.7;scene.world=world center=(minimum+maximum)/2;extent=maximum.z-minimum.z camera=bpy.data.objects.new('AuditCamera',bpy.data.cameras.new('AuditCamera'));scene.collection.objects.link(camera);camera.location=center+Vector((.2,-3,1))*extent;camera.rotation_euler=(center-camera.location).to_track_quat('-Z','Y').to_euler();camera.data.type='ORTHO';camera.data.ortho_scale=extent*1.5;scene.camera=camera for location,power in [((2,-3,4),500),((-3,-1,2),300)]: light=bpy.data.objects.new('AuditLight',bpy.data.lights.new('AuditLight','AREA'));scene.collection.objects.link(light);light.location=center+Vector(location)*extent;light.rotation_euler=(center-light.location).to_track_quat('-Z','Y').to_euler();light.data.energy=power;light.data.shape='DISK';light.data.size=extent*3 scene.render.filepath=str(folder/('audit_'+Path(name).stem+'.png'));bpy.ops.render.render(write_still=True) (folder/'stage_geometry.json').write_text(json.dumps(reports,indent=2),encoding='utf-8')