Files
Portfolio/assets/blender/districts/export-districts.py

68 lines
2.9 KiB
Python

"""Export the district kit to the runtime GLB (positions + indices only).
blender -b assets/blender/districts/nightdrive-districts.blend --python assets/blender/districts/export-districts.py [-- --preview out.png]
Normals are derived per fragment at runtime (flat shading from screen-space
derivatives), so the GLB carries no normals, UVs or materials and shared box
corners stay welded. Writes provenance next to this script.
"""
import bpy, json, hashlib, sys, math
from pathlib import Path
here = Path(__file__).resolve().parent
root = here.parents[2]
scene = bpy.data.scenes['Roadside Districts']
output = root / 'src/assets/nightdrive-districts.glb'
for obj in scene.objects:
obj.select_set(True)
bpy.ops.export_scene.gltf(
filepath=str(output), export_format='GLB', use_selection=True, use_active_scene=True,
export_apply=True, export_normals=False, export_texcoords=False, export_materials='NONE',
export_animations=False, export_cameras=False, export_lights=False, export_yup=True,
)
triangles = 0
for obj in scene.objects:
obj.data.calc_loop_triangles()
triangles += len(obj.data.loop_triangles)
provenance = {
'asset': 'Nightdrive roadside districts',
'source': 'nightdrive-districts.blend',
'authorship': 'Original procedural modelling in Blender for this portfolio (author-districts.py); no external assets.',
'editable_scene': 'Roadside Districts',
'pieces': sorted({o.name.rsplit('_', 1)[0] for o in scene.objects}),
'triangles': triangles,
'attributes': 'POSITION + indices; flat normals derived at runtime',
'export': '../../../src/assets/nightdrive-districts.glb',
'sha256': hashlib.sha256(output.read_bytes()).hexdigest(),
}
(here / 'nightdrive-districts.asset.json').write_text(json.dumps(provenance, indent=2) + '\n')
print(json.dumps(provenance))
if '--preview' in sys.argv:
target = sys.argv[sys.argv.index('--preview') + 1]
names = provenance['pieces']
for i, name in enumerate(names):
for suffix in ('body', 'light'):
obj = scene.objects[f'{name}_{suffix}']
obj.location = ((i % 4) * 34 - 50, (i // 4) * 40, 0)
mat = bpy.data.materials.new(f'preview-{suffix}')
mat.diffuse_color = (0.05, 0.05, 0.08, 1) if suffix == 'body' else (0.1, 0.9, 1.0, 1)
obj.data.materials.append(mat)
cam = bpy.data.objects.new('preview-cam', bpy.data.cameras.new('preview-cam'))
scene.collection.objects.link(cam)
cam.location = (95, -95, 70)
cam.rotation_euler = (math.radians(58), 0, math.radians(45))
cam.data.lens = 30
scene.camera = cam
try:
scene.render.engine = 'BLENDER_WORKBENCH'
except TypeError as e:
print(e)
scene.display.shading.color_type = 'MATERIAL'
scene.display.shading.light = 'STUDIO'
scene.display.shading.show_cavity = True
scene.render.resolution_x, scene.render.resolution_y = 1600, 1000
scene.render.filepath = target
bpy.ops.render.render(write_still=True)