"""Export isolated authored source into material batches; leave lookdev editable.""" import bpy, json, hashlib from mathutils import Matrix, Vector from pathlib import Path root_path=Path(__file__).resolve().parents[3] scene=bpy.data.scenes['Midnight Expressway'] bpy.context.window.scene=scene export_scene=bpy.data.scenes.new('Expressway Export') root=bpy.data.objects.new('evolution-chase-car',None); export_scene.collection.objects.link(root) names={'M_Body_Gunmetal':'car-body','M_Body_Haunch':'body-haunches','M_Glass_Smoke':'rear-glass','M_Rear_Light':'rear-light-bar','M_Cyan_Accent':'car-underglow-source','M_Lower_Graphite':'body-trim','M_Wheel':'wheel-machining','M_Tire':'tires'} depsgraph=bpy.context.evaluated_depsgraph_get(); groups={} for obj in scene.objects: if obj.type not in ['MESH','CURVE'] or obj.name.startswith('LOOKDEV'): continue evaluated=obj.evaluated_get(depsgraph) mesh=bpy.data.meshes.new_from_object(evaluated,depsgraph=depsgraph); mesh.transform(obj.matrix_world) clone=bpy.data.objects.new('export-'+obj.name,mesh); export_scene.collection.objects.link(clone) key=obj.data.materials[0].name.split('.')[0] wheel=None for axle in ['front','rear']: for side in ['left','right']: if any(token in obj.name for token in [f'{axle}-wheel-{side}', f'{axle}-rim-{side}', f'{axle}-rim-ring-{side}', f'wheel-{axle}-{side}']): wheel=f'wheel-{axle}-{side}' groups.setdefault((key,wheel),[]).append(clone) bpy.context.window.scene=export_scene wheel_roots={} for (key,wheel),objects in groups.items(): bpy.ops.object.select_all(action='DESELECT') for obj in objects: obj.select_set(True) bpy.context.view_layer.objects.active=objects[0] if len(objects)>1: bpy.ops.object.join() joined=bpy.context.object; joined.name='evolution-'+names[key] if wheel: if wheel not in wheel_roots: axle='front' if 'front' in wheel else 'rear'; side=-1 if 'left' in wheel else 1 wheel_root=bpy.data.objects.new(wheel,None); export_scene.collection.objects.link(wheel_root) wheel_root.parent=root; wheel_root.location=(side*1.01,-1.62 if axle=='front' else 1.62,.42 if axle=='front' else .46) wheel_roots[wheel]=wheel_root wheel_root=wheel_roots[wheel] joined.data.transform(Matrix.Translation(-wheel_root.location)) joined.parent=wheel_root else: joined.parent=root bpy.ops.object.select_all(action='SELECT') output=root_path/'src/assets/nightdrive-grand-tourer-expressway.glb' bpy.ops.export_scene.gltf(filepath=str(output),export_format='GLB',use_selection=True,use_active_scene=True,export_apply=True,export_animations=False,export_cameras=False,export_lights=False) triangles=0 for obj in export_scene.objects: if obj.type=='MESH': obj.data.calc_loop_triangles(); triangles+=len(obj.data.loop_triangles) provenance={'asset':'Nightdrive expressway grand tourer','source':'nightdrive-expressway.blend','base':'../evolution/nightdrive-evolution.blend at c9ac36e','authorship':'Original procedural modelling in Blender for this portfolio; no external assets or generated project evidence.','editable_scene':'Midnight Expressway','material_groups':len(groups),'independent_wheels':4,'triangles':triangles,'export':'../../../src/assets/nightdrive-grand-tourer-expressway.glb','sha256':hashlib.sha256(output.read_bytes()).hexdigest()} (root_path/'assets/blender/expressway/nightdrive-expressway.asset.json').write_text(json.dumps(provenance,indent=2)+'\n') bpy.context.window.scene=scene print(json.dumps(provenance))