saumwacht-godot/assets-source/phase10/bake_bark.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

61 lines
4 KiB
Python

"""Render authored, periodic 4D wood grain at native 4096px in Blender.
This is a procedural material bake, not an enlargement of a bitmap.
The torus coordinate mapping makes the material seamless on all four edges.
"""
import bpy, math, json
from pathlib import Path
PROJECT=Path(__file__).resolve().parents[2]
out=PROJECT/'assets/materials/phase10'
scene=bpy.data.scenes.new('Bark_PBR_4K');bpy.context.window.scene=scene
scene.render.engine='CYCLES';scene.cycles.samples=1
scene.render.resolution_x=4096;scene.render.resolution_y=4096;scene.render.resolution_percentage=100
scene.render.image_settings.file_format='PNG';scene.render.image_settings.color_mode='RGB';scene.render.image_settings.color_depth='8'
scene.render.image_settings.compression=90;scene.render.dither_intensity=0
scene.view_settings.view_transform='Standard';scene.view_settings.look='None'
scene.render.film_transparent=False
bpy.ops.mesh.primitive_plane_add(size=2)
plane=bpy.context.object;plane.name='Bark_material_bake_surface'
mat=bpy.data.materials.new('SW_4K_Sculpted_Oak');mat.use_nodes=True;plane.data.materials.append(mat)
n=mat.node_tree.nodes;n.clear();links=mat.node_tree.links
def node(kind): return n.new(kind)
def mathnode(op,a,b=None):
obj=node('ShaderNodeMath');obj.operation=op
if isinstance(a,(float,int)): obj.inputs[0].default_value=a
else: links.new(a,obj.inputs[0])
if b is not None:
if isinstance(b,(float,int)):obj.inputs[1].default_value=b
else:links.new(b,obj.inputs[1])
return obj.outputs[0]
uv=node('ShaderNodeTexCoord');split=node('ShaderNodeSeparateXYZ');links.new(uv.outputs['UV'],split.inputs[0])
u=mathnode('MULTIPLY',split.outputs['X'],math.tau)
v=mathnode('MULTIPLY',split.outputs['Y'],math.tau)
co=node('ShaderNodeCombineXYZ')
links.new(mathnode('MULTIPLY',mathnode('COSINE',u),10),co.inputs['X'])
links.new(mathnode('MULTIPLY',mathnode('SINE',u),10),co.inputs['Y'])
links.new(mathnode('MULTIPLY',mathnode('COSINE',v),.7),co.inputs['Z'])
grain=node('ShaderNodeTexNoise');grain.noise_dimensions='4D'
links.new(co.outputs[0],grain.inputs['Vector']);links.new(mathnode('MULTIPLY',mathnode('SINE',v),.7),grain.inputs['W'])
grain.inputs['Scale'].default_value=2.6;grain.inputs['Detail'].default_value=7;grain.inputs['Roughness'].default_value=.73
height=node('ShaderNodeValToRGB')
height.color_ramp.elements[0].position=.27;height.color_ramp.elements[0].color=(.07,.07,.07,1)
height.color_ramp.elements[1].position=.67;height.color_ramp.elements[1].color=(.8,.8,.8,1)
height.color_ramp.elements.new(.43).color=(.14,.14,.14,1)
height.color_ramp.elements.new(.51).color=(.55,.55,.55,1)
links.new(grain.outputs['Fac'],height.inputs[0])
emit=node('ShaderNodeEmission');output=node('ShaderNodeOutputMaterial');links.new(emit.outputs[0],output.inputs['Surface'])
links.new(height.outputs[0],emit.inputs['Color'])
bpy.ops.object.camera_add(location=(0,0,3));camera=bpy.context.object;camera.data.type='ORTHO';camera.data.ortho_scale=2;scene.camera=camera
scene.render.filepath=str(out/'oak-height-4k.png');bpy.ops.render.render(write_still=True)
colors=node('ShaderNodeValToRGB')
def linear(hexcolor):
rgb=[int(hexcolor[i:i+2],16)/255 for i in (0,2,4)]
return tuple(c/12.92 if c<=.04045 else ((c+.055)/1.055)**2.4 for c in rgb)+(1,)
colors.color_ramp.elements[0].position=.0;colors.color_ramp.elements[0].color=linear('302B23')
colors.color_ramp.elements[1].position=1;colors.color_ramp.elements[1].color=linear('B09A6D')
colors.color_ramp.elements.new(.18).color=linear('4B3C2A')
colors.color_ramp.elements.new(.51).color=linear('766041')
colors.color_ramp.elements.new(.74).color=linear('94855D')
links.new(height.outputs[0],colors.inputs[0]);links.new(colors.outputs[0],emit.inputs['Color'])
scene.render.filepath=str(out/'oak-albedo-4k.png');bpy.ops.render.render(write_still=True)
bpy.data.libraries.write(str(PROJECT/'assets-source/phase10/oak-material-4k.blend'),{scene},fake_user=True,compress=True)
print('PBR_BAKE_PASS: two native 4096 x 4096 8-bit runtime maps; original seamless procedural material.')