saumwacht-godot/scripts/presentation/forged_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

48 lines
1.9 KiB
Text

shader_type spatial;
render_mode diffuse_burley, specular_schlick_ggx;
uniform vec4 base_color : source_color = vec4(.28,.29,.31,1.0);
uniform float metalness = 0.0;
uniform float base_roughness = .78;
uniform float grain_amount = .08;
uniform sampler2D rock_map : source_color, filter_linear_mipmap_anisotropic, repeat_enable;
varying vec3 local_position;
varying vec3 local_normal;
float hash3(vec3 p) {
p = fract(p * .1031);
p += dot(p, p.yzx + 33.33);
return fract((p.x + p.y) * p.z);
}
float noise3(vec3 p) {
vec3 i = floor(p);
vec3 f = fract(p);
f = f*f*(3.0-2.0*f);
return mix(mix(mix(hash3(i),hash3(i+vec3(1,0,0)),f.x),mix(hash3(i+vec3(0,1,0)),hash3(i+vec3(1,1,0)),f.x),f.y),
mix(mix(hash3(i+vec3(0,0,1)),hash3(i+vec3(1,0,1)),f.x),mix(hash3(i+vec3(0,1,1)),hash3(i+vec3(1,1,1)),f.x),f.y),f.z);
}
void vertex() {
local_position = VERTEX;
local_normal = NORMAL;
}
void fragment() {
float veins = noise3(local_position * 16.0);
float grain = noise3(local_position * 100.0);
float detail_fade = 1.0-smoothstep(.008,.03,length(fwidth(local_position)));
grain = mix(.5,grain,detail_fade);
float weather = smoothstep(.40,.62,veins);
ALBEDO = base_color.rgb * (1.0 - grain_amount + weather * grain_amount * 1.2);
vec3 w=pow(abs(local_normal),vec3(5.0)); w/=max(dot(w,vec3(1.0)),.0001);
vec3 p=local_position*1.5;
vec3 rock=texture(rock_map,p.xy).rgb*w.z+texture(rock_map,p.xz).rgb*w.y+texture(rock_map,p.zy).rgb*w.x;
if(metalness < .25) { ALBEDO *= .64 + rock*1.45; grain = dot(rock,vec3(.333)); }
ROUGHNESS = clamp(base_roughness + (grain-.5)*grain_amount, .15, .95);
METALLIC = metalness;
// Sparse pits affect fine normal response while all large detail is geometry.
vec3 n = NORMAL;
vec3 dpdx = dFdx(VERTEX), dpdy = dFdy(VERTEX);
vec3 rx = cross(dpdy,n), ry = cross(n,dpdx);
float determinant = dot(dpdx,rx);
vec3 gradient = (dFdx(grain)*rx + dFdy(grain)*ry);
NORMAL = normalize(abs(determinant)*n - sign(determinant)*gradient*grain_amount*.012);
}