Files
Portfolio/assets/blender/expressway/export-expressway.py
LucaP b188cac7ed feat: sculpt portfolio into an immersive midnight expressway
Author physical road furniture, layered terrain and atmosphere, projected illuminated route signs, and detailed Blender coachwork. Refine camera mass, wheel contact, chapter composition, and compact reading space while preserving approved content and audio contracts.

Include isolated Blender source, before/after and hardware Chrome motion evidence, preservation hashes, validated preview checks, and documented inherited unit failures.
2026-09-05 05:10:17 +03:00

52 lines
3.5 KiB
Python

"""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))