feat: evolve portfolio into an authored midnight grand tour

This commit is contained in:
2026-09-05 03:55:18 +03:00
parent 642f5b583d
commit c9ac36e249
41 changed files with 812 additions and 65 deletions

View File

@@ -0,0 +1,66 @@
"""Second design pass; run inside Blender with Portfolio Evolution loaded.
Re-running replaces only this pass's objects. Keeps the eight material groups.
"""
import bpy
import math
from pathlib import Path
root_path = Path(__file__).resolve().parents[3]
scene = bpy.data.scenes['Portfolio Evolution']
bpy.context.window.scene = scene
car = next(o for o in scene.objects if o.name.split('.')[0] == 'chase-car')
materials = {m.name.split('.')[0]: m for o in scene.objects if o.type == 'MESH' for m in o.data.materials}
for obj in list(scene.objects):
if obj.name.startswith('signature-'):
bpy.data.objects.remove(obj, do_unlink=True)
def finish(obj, name, material, bevel=0.008):
obj.name = 'signature-' + name
obj.parent = car
obj.data.materials.append(materials[material])
if bevel:
mod = obj.modifiers.new('Soft machined edge', 'BEVEL')
mod.width = bevel
mod.segments = 2
obj.modifiers.new('Weighted normals', 'WEIGHTED_NORMAL')
return obj
def box(name, location, dimensions, material, bevel=0.008):
bpy.ops.mesh.primitive_cube_add(size=1, location=location)
obj = bpy.context.object
obj.dimensions = dimensions
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
return finish(obj, name, material, bevel)
# A swept floating wing. Its high tips and low center echo the body haunches.
outline = [(-1.22, 2.28), (-0.98, 2.08), (-0.72, 2.13),
(0.72, 2.13), (0.98, 2.08), (1.22, 2.28),
(1.18, 2.51), (0.72, 2.42), (-0.72, 2.42), (-1.18, 2.51)]
n = len(outline)
verts = [(x, y, 1.20 + (0.06 if abs(x) > 0.95 else 0) + dz)
for dz in [0, 0.065] for x, y in outline]
faces = [tuple(reversed(range(n))), tuple(range(n, 2*n))]
faces += [(i, (i+1)%n, (i+1)%n+n, i+n) for i in range(n)]
mesh = bpy.data.meshes.new('Swept aerofoil')
mesh.from_pydata(verts, [], faces)
mesh.update()
wing = bpy.data.objects.new('Swept wing', mesh)
scene.collection.objects.link(wing)
finish(wing, 'floating-wing', 'M_Body_Haunch', 0.018)
for side in [-1, 1]:
box('wing-pylon', (side*0.66, 2.27, 1.045), (0.075, 0.14, 0.35), 'M_Lower_Graphite')
box('wing-endplate', (side*1.185, 2.35, 1.245), (0.045, 0.30, 0.20), 'M_Body_Gunmetal')
box('wing-marker', (side*1.212, 2.37, 1.28), (0.014, 0.19, 0.025), 'M_Cyan_Accent', 0.003)
# Illuminated outer guides frame the dark diffuser, below the coral lamp.
box('rear-guide-housing', (side*0.88, 2.56, 0.50), (0.07, 0.23, 0.235), 'M_Lower_Graphite')
box('rear-guide', (side*0.88, 2.678, 0.50), (0.022, 0.02, 0.19), 'M_Cyan_Accent', 0.004)
for y, z in [(-1.62, 0.42), (1.62, 0.46)]:
# Eight swept metallic vanes sit inside each original rim ring.
for index in range(8):
angle = index * math.tau / 8
obj = box('turbine-vane', (side*1.186, y+math.sin(angle)*0.19, z+math.cos(angle)*0.19),
(0.022, 0.064, 0.19), 'M_Wheel', 0.005)
obj.rotation_euler.x = -angle + side*0.3
bpy.data.libraries.write(str(root_path / 'assets/blender/evolution/nightdrive-evolution.blend'), {scene}, fake_user=True, compress=True)
exec(compile((root_path / 'assets/blender/evolution/export-grand-tourer.py').read_text(), str(root_path / 'assets/blender/evolution/export-grand-tourer.py'), 'exec'))