66 lines
3.2 KiB
Python
66 lines
3.2 KiB
Python
"""Run in Blender, not system Python:
|
|
blender --background --python blender/prepare_model.py
|
|
Creates an editable .blend next to this script. Existing scene is replaced.
|
|
Keeps every configuration variant; helper collections are hidden in viewport.
|
|
"""
|
|
from pathlib import Path
|
|
import json
|
|
import bpy
|
|
|
|
ROOT=Path(__file__).resolve().parent.parent
|
|
SOURCE=ROOT/'models'/'dum.glb'
|
|
TARGET=Path(__file__).resolve().parent/'dum_locenice.blend'
|
|
if not SOURCE.is_file():
|
|
raise FileNotFoundError(SOURCE)
|
|
if TARGET.exists():
|
|
raise FileExistsError(f'Rename or remove {TARGET} before running again.')
|
|
bpy.ops.wm.read_factory_settings(use_empty=True)
|
|
bpy.ops.import_scene.gltf(filepath=str(SOURCE))
|
|
defaults=json.loads((ROOT/'data'/'catalog.json').read_text())['defaults']
|
|
scene=bpy.context.scene
|
|
scene.unit_settings.system='METRIC'
|
|
scene.unit_settings.scale_length=1.0
|
|
collections={}
|
|
for name in ['01_Exterior','02_Interior_walls','03_Kitchen_and_furniture','04_Site','05_Cutaway_alternatives','06_Standards_alternatives']:
|
|
col=bpy.data.collections.new(name);scene.collection.children.link(col);collections[name]=col
|
|
for obj in list(scene.objects):
|
|
if obj.type!='MESH':continue
|
|
props=obj
|
|
if props.get('stdHidden') or props.get('stdWhen') or props.get('stdBlind'):
|
|
key='06_Standards_alternatives'
|
|
elif props.get('interiorLayer') in ['cut','cutShell']:
|
|
key='05_Cutaway_alternatives'
|
|
elif props.get('interiorLayer')=='furniture':
|
|
key='03_Kitchen_and_furniture'
|
|
elif props.get('interiorLayer'):
|
|
key='02_Interior_walls'
|
|
elif props.get('siteLayer') or props.get('legacySite'):
|
|
key='04_Site'
|
|
else:key='01_Exterior'
|
|
for c in list(obj.users_collection):c.objects.unlink(obj)
|
|
collections[key].objects.link(obj)
|
|
# Stable ID comes from the GLB extras. Do not delete it during future editing.
|
|
obj['locenice_edit_note']='Keep loceniceId and configuration properties.'
|
|
condition=props.get('stdWhen',{})
|
|
hidden=bool(props.get('stdHidden')) or bool(props.get('stdBlind') and not defaults['blinds'])
|
|
if hasattr(condition,'items'):
|
|
hidden=hidden or any(defaults.get(k)!=v for k,v in condition.items())
|
|
obj.hide_set(hidden)
|
|
obj.hide_render=hidden
|
|
collections['05_Cutaway_alternatives'].hide_viewport=True
|
|
# Keep matching default variants visible; all alternatives remain in the file.
|
|
note=bpy.data.texts.new('READ_ME_Locenice')
|
|
note.write('''This is a visualisation mesh, not BIM. Units: metres.
|
|
The source includes multiple, mutually exclusive variants in the same location.
|
|
Use named collections to inspect them. Do not join all meshes or all materials.
|
|
loceniceId, stdWhen, stdBlind, windowNode and interiorLayer must stay on objects.
|
|
Detailed construction dimensions come from the project, not reference photos.
|
|
After exporting all variants to GLB, run tools/prepare_export.py.
|
|
Blender reorders glTF nodes, materials and textures. The included web manifest
|
|
is indexed for the supplied GLB; the preparation tool rebinds stable IDs.
|
|
A changed wall or cabinet also requires checking web collision volumes / camera presets.
|
|
''')
|
|
scene['locenice_metadata_json']=json.dumps(json.loads((ROOT/'data'/'scene.json').read_text()),ensure_ascii=False)
|
|
bpy.ops.wm.save_as_mainfile(filepath=str(TARGET))
|
|
print('Saved:',TARGET)
|