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