saumwacht-godot/assets-source/phase10/finalize_sources.py
Martin Stickelbroeck c2b447610c Baseline: Saumwacht 0.15.0 (Phase 20A) vor dem Umbau zu Champions of Luneraria
Unveränderter Ausgangsstand inklusive Masterprompt und Konzeptbildern
unter assets/. .godot/ und docs/screenshots/ bleiben laut .gitignore
unversioniert; letztere sind unter ../backups gesichert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 20:00:36 +02:00

39 lines
2.6 KiB
Python

import bpy,json,sys
from pathlib import Path
p=Path(__file__).resolve().parents[2];source=p/'assets-source/phase4'
sys.path.insert(0,str(source/'blender'))
from reference_sculpt_detail import add_offline_materials
for path in sorted((source/'records').glob('*.json')):
record=json.loads(path.read_text())
if record['faction'] not in ['wurzelbund','glutpakt','rift'] and record['role'] not in ['worker','core']:continue
with bpy.data.libraries.load(record['blend_path'],link=False) as (frm,to):to.scenes=frm.scenes
objects=[o for scene in to.scenes for o in scene.objects if o.type=='MESH']
add_offline_materials(objects,p)
# Keep source image references relative to the .blend location.
bpy.data.libraries.write(record['blend_path'],set(to.scenes),path_remap='RELATIVE_ALL',fake_user=True,compress=True)
record['offline_sculpt_parts']=sum(bool(o.get('sculpt_surface')) for o in objects)
record['offline_render_triangles']=0
for obj in objects:
obj.data.calc_loop_triangles();record['offline_render_triangles']+=len(obj.data.loop_triangles)*(16 if obj.get('sculpt_surface') else 1)
path.write_text(json.dumps(record,ensure_ascii=False,indent=2)+'\n')
for scene in to.scenes:bpy.data.scenes.remove(scene)
for obj in objects:
if not obj.users:bpy.data.objects.remove(obj)
from pipeline import write_manifest
write_manifest()
print('BLENDER_PBR_SOURCE_PASS: 33 independent scenes with editable high-resolution geometry and material nodes.')
# Environment source keeps its original 2586 independently editable objects.
map_path=p/'assets-source/phase10/verdant-rift.blend'
with bpy.data.libraries.load(str(map_path),link=False) as (frm,to):to.scenes=frm.scenes
materials={m for scene in to.scenes for obj in scene.objects if obj.type=='MESH' for m in obj.data.materials if m}
for mat in materials:
if mat.get('phase10_pbr') or not any(k in mat.name for k in ['limestone','cliff','paving']):continue
nodes=mat.node_tree.nodes;links=mat.node_tree.links;bsdf=nodes.get('Principled BSDF')
texture=nodes.new('ShaderNodeTexImage');texture.image=bpy.data.images.load(str(p/'assets/materials/phase10/limestone-albedo.png'),check_existing=True);texture.projection='BOX';texture.projection_blend=.3
coord=nodes.new('ShaderNodeTexCoord');links.new(coord.outputs['Object'],texture.inputs['Vector'])
bump=nodes.new('ShaderNodeBump');bump.inputs['Strength'].default_value=.3;bump.inputs['Distance'].default_value=.04
links.new(texture.outputs['Color'],bump.inputs['Height']);links.new(bump.outputs['Normal'],bsdf.inputs['Normal'])
mat['phase10_pbr']=True
bpy.data.libraries.write(str(map_path),set(to.scenes),path_remap='RELATIVE_ALL',fake_user=True,compress=True)
print('ENVIRONMENT_PBR_SOURCE_PASS')