Files
rhinelab-ui/art/build_assembly.py
T

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}))