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

58 lines
2.2 KiB
Text

shader_type spatial;
// The imported AB/BB/QG surfaces are double-sided, including thin foliage.
render_mode diffuse_burley, specular_schlick_ggx, cull_disabled;
uniform float roughness_value : hint_range(0, 1) = 0.75;
uniform float metallic_value : hint_range(0, 1) = 0.0;
uniform float grain_amount = 0.08;
uniform float grain_scale = 90.0;
uniform float relief_depth = 0.00045;
// 0 mineral, 1 leather, 2 fabric, 3 bark, 4 leaf, 5 metal.
uniform int surface_kind = 0;
float hash21(vec2 p) {
p = fract(p * vec2(123.34, 456.21));
p += dot(p, p + 45.32);
return fract(p.x * p.y);
}
float grain_noise(vec2 p) {
vec2 cell = floor(p);
vec2 f = fract(p);
vec2 blend = f * f * (3.0 - 2.0 * f);
return mix(mix(hash21(cell), hash21(cell + vec2(1.0, 0.0)), blend.x),
mix(hash21(cell + vec2(0.0, 1.0)), hash21(cell + vec2(1.0)), blend.x), blend.y);
}
void fragment() {
if (!FRONT_FACING) { NORMAL = -NORMAL; }
vec2 p = UV * grain_scale;
float footprint = max(length(dFdx(p)), length(dFdy(p)));
float detail = 1.0 - smoothstep(0.5, 2.0, footprint);
float coarse = grain_noise(p * 0.37);
float fine = grain_noise(p) * 0.65 + grain_noise(p * 2.03 + 19.7) * 0.35;
float grain = mix(0.0, fine - 0.5, detail);
float relief = grain;
if (surface_kind == 2) {
// Subpixel weave fades out instead of producing a moving checkerboard.
float weave = sin(p.x * 6.28318) * sin(p.y * 6.28318);
relief += weave * detail * 0.1;
} else if (surface_kind == 3) {
relief = (grain_noise(vec2(p.x, p.y * 0.12)) - 0.5) * detail;
} else if (surface_kind == 4) {
relief *= 0.2;
BACKLIGHT = COLOR.rgb * 0.12;
} else if (surface_kind == 5) {
relief = (grain_noise(vec2(p.x * 0.1, p.y)) - 0.5) * detail * 0.2;
}
ALBEDO = COLOR.rgb * (1.0 + grain * grain_amount + (coarse - 0.5) * grain_amount * 0.35);
ROUGHNESS = clamp(roughness_value + grain * 0.07, 0.08, 1.0);
METALLIC = metallic_value;
// Surface gradient in view space; preserves authored UVs while joints deform.
vec3 dx = dFdx(VERTEX), dy = dFdy(VERTEX);
vec3 rx = cross(dy, NORMAL), ry = cross(NORMAL, dx);
float determinant = dot(dx, rx);
if (abs(determinant) > 0.00000001) {
NORMAL = normalize(abs(determinant) * NORMAL - sign(determinant) *
(dFdx(relief) * rx + dFdy(relief) * ry) * relief_depth);
}
}