67 lines
3.2 KiB
Python
67 lines
3.2 KiB
Python
"""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'))
|