58 lines
3.2 KiB
Python
58 lines
3.2 KiB
Python
import bpy
|
|
from pathlib import Path
|
|
BUILD_ROOT = Path(__file__).resolve().parents[1]
|
|
ROOT = BUILD_ROOT
|
|
source = (ROOT/'art/build_archive.py').read_text(encoding='utf-8')
|
|
prefix = source.split('# Convert text, bake modifiers')[0]
|
|
prefix = prefix.replace("scene = bpy.data.scenes.new('Rhine_Archive_Work')", "scene = bpy.data.scenes.new('Rhine_Assembly_Work')")
|
|
prefix = prefix.replace("if old != scene and old.name.startswith('Rhine_Archive_Asset'):", "if False:")
|
|
prefix = prefix.replace("scene.name='Rhine_Archive_Asset'", "scene.name='Rhine_Assembly_Asset'")
|
|
exec(compile(prefix, str(ROOT/'art/build_archive.py'), 'exec'))
|
|
ROOT = BUILD_ROOT
|
|
def part_for(name):
|
|
if name.startswith(('Rear translucent carrier', 'Polished perimeter rail', 'Ivory spine cap', 'Carrier mating seam')):
|
|
return 'carrier'
|
|
if name.startswith('Information substrate'): return 'substrate'
|
|
if name.startswith(('Embedded optical cavity', 'Embedded amber annulus', 'Folded optical tab')): return 'optical-core'
|
|
if name.startswith(('Subsurface refractive shoulder', 'Inner optical bevel', 'Concentric optical machining', 'Optical ribbon')):
|
|
return 'optical-lenses'
|
|
if name.startswith(('Countersunk washer', 'Machined screw', 'Screw slot')): return 'fasteners'
|
|
return 'cover'
|
|
for obj in list(scene.objects):
|
|
obj['assemblyPart'] = part_for(obj.name)
|
|
bpy.context.view_layer.objects.active = obj
|
|
bpy.ops.object.select_all(action='DESELECT')
|
|
obj.select_set(True)
|
|
if obj.type in ['FONT','CURVE']: bpy.ops.object.convert(target='MESH')
|
|
for mod in list(obj.modifiers):
|
|
bpy.ops.object.modifier_apply(modifier=mod.name)
|
|
if obj.data.materials[0].name.split('.')[0] == 'Carbon_Ink':
|
|
bpy.data.objects.remove(obj, do_unlink=True)
|
|
pairs = {}
|
|
for obj in scene.objects:
|
|
key = (obj['assemblyPart'], obj.data.materials[0].name)
|
|
pairs.setdefault(key, []).append(obj)
|
|
for (part, surface), objects in pairs.items():
|
|
bpy.ops.object.select_all(action='DESELECT')
|
|
for obj in objects: obj.select_set(True)
|
|
bpy.context.view_layer.objects.active = objects[0]
|
|
bpy.ops.object.join()
|
|
obj = bpy.context.object
|
|
obj.name = part+'__'+surface.split('.')[0]
|
|
obj['assemblyPart'] = part
|
|
scene.cursor.location = (0,0,0)
|
|
bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
|
|
bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
|
|
if surface.startswith(('Optical_Glass_', 'Optical_Bridge_Glass', 'Amber_Optical_Inlay')):
|
|
obj.scale.y *= 2.0
|
|
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
|
|
else:
|
|
for vertex in obj.data.vertices:vertex.co.y *= 2.0
|
|
bpy.ops.object.select_all(action='SELECT')
|
|
export_path=ROOT/'art/.cache/archive-assembly.glb'
|
|
export_path.parent.mkdir(parents=True,exist_ok=True)
|
|
bpy.ops.export_scene.gltf(filepath=str(export_path), export_format='GLB', use_selection=True, use_active_scene=True, export_apply=True, export_extras=True)
|
|
os.replace(str(export_path),str(ROOT/'public/assets/archive-assembly.glb'))
|
|
bpy.data.libraries.write(str(ROOT/'art/archive-assembly.blend'), {scene}, fake_user=True)
|
|
print('Assembly exported:', len(scene.objects), 'meshes, parts:', sorted({o['assemblyPart'] for o in scene.objects}))
|