saumwacht-godot/scripts/presentation/living_material.gdshader
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

55 lines
2.4 KiB
Text

shader_type spatial;
render_mode diffuse_burley, specular_schlick_ggx;
uniform vec4 base_color : source_color;
uniform float base_roughness = .85;
uniform bool bark = false;
uniform bool endgrain = false;
uniform bool moss = false;
uniform sampler2D oak_color : source_color, filter_linear_mipmap_anisotropic, repeat_enable;
uniform sampler2D oak_height : filter_linear_mipmap_anisotropic, repeat_enable;
varying vec3 position_model;
varying vec3 local_normal;
float hash(vec3 p) { p=fract(p*.1031); p+=dot(p,p.yzx+33.33); return fract((p.x+p.y)*p.z); }
float noise(vec3 p) {
vec3 i=floor(p),f=fract(p); f=f*f*(3.0-2.0*f);
return mix(mix(mix(hash(i),hash(i+vec3(1,0,0)),f.x),mix(hash(i+vec3(0,1,0)),hash(i+vec3(1,1,0)),f.x),f.y),mix(mix(hash(i+vec3(0,0,1)),hash(i+vec3(1,0,1)),f.x),mix(hash(i+vec3(0,1,1)),hash(i+vec3(1,1,1)),f.x),f.y),f.z);
}
void vertex() { position_model=VERTEX; local_normal=NORMAL; }
void fragment() {
vec3 p=position_model;
float mottling=noise(p*15.0);
float detail=noise(p*(bark ? vec3(105.0,12.0,105.0) : vec3(70.0)));
float fade=1.0-smoothstep(.005,.025,length(fwidth(p)));
detail=mix(.5,detail,fade);
float fissure=bark ? smoothstep(.36,.50,detail) : detail;
ALBEDO=base_color.rgb*mix(.64,1.04,mottling)*mix(.72,1.0,fissure);
if(bark) {
vec3 w=pow(abs(local_normal),vec3(6.0)); w/=max(dot(w,vec3(1)),.0001);
vec3 q=p*vec3(1.3,.72,1.3);
vec3 oak=texture(oak_color,q.zy).rgb*w.x+texture(oak_color,q.xz).rgb*w.y+texture(oak_color,q.xy).rgb*w.z;
detail=texture(oak_height,q.zy).r*w.x+texture(oak_height,q.xz).r*w.y+texture(oak_height,q.xy).r*w.z;
ALBEDO=base_color.rgb*(.60+oak*2.0);
} else {
ALBEDO=base_color.rgb*mix(.78,1.12,mottling);
BACKLIGHT=base_color.rgb*.20;
}
if(moss) {
float carpet=noise(p*48.0)*.6+noise(p*11.0)*.4;
ALBEDO=base_color.rgb*mix(.60,1.2,carpet);
detail=carpet;
}
if(endgrain) {
vec2 q=UV-vec2(.5); float a=atan(q.y,q.x);
float radius=length(q)*(1.0+.03*sin(a*3.0)+.02*cos(a*7.0));
float rings=sin(radius*210.0+sin(a*9.0)*.13)*.5+.5;
ALBEDO=base_color.rgb*mix(.76,1.08,rings)*mix(.90,1.03,noise(vec3(UV*150.0,0.0)));
detail=rings;
}
ROUGHNESS=clamp(base_roughness+(detail-.5)*.20,.5,1.0);
METALLIC=0.0;
vec3 n=NORMAL,dx=dFdx(VERTEX),dy=dFdy(VERTEX);
vec3 rx=cross(dy,n),ry=cross(n,dx);
float det=dot(dx,rx);
vec3 gradient=dFdx(detail)*rx+dFdy(detail)*ry;
NORMAL=normalize(abs(det)*n-sign(det)*gradient*(bark ? .006 : .0003));
}