Top windet sich über das Hochland, Mid quert die Kluft über die Mittelplattform, Bottom führt durch das Tiefland über die Deltabrücke; Top und Bottom sind exakt gleich lang, alles bleibt spiegelsymmetrisch. LuneTerrain liefert ein exakt gespiegeltes Höhenfeld, auf dem Figuren stehen. Bossgrotte als Terrasse auf der Achse zwischen Top und Mid, Aufmarschbereiche je Lane, perspektivische Kamera mit Sprungtasten (F2–F4, B, G, H, O, R, Q/E). Bestandsassets wiederverwendet, neue Formen als Blockout für G2/G4. Geprüft: verify_g1 443/443, Regeln 91/91, M2 73/73, verify_m1 38/38, verify_m2 14/14, Netz 43/43, Loopback 12/12, Balance 40 Partien (Seitentausch 20/20), Legacy 209/463. Vorher/Nachher-Aufnahmen und Messungen in G1-KARTE.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
36 lines
1.8 KiB
Text
36 lines
1.8 KiB
Text
// G1 ground: zone colours from the height field (vertex colour), rockiness in alpha.
|
|
// Rock areas use the shared limestone texture triplanar, like the Kluft surfaces.
|
|
shader_type spatial;
|
|
render_mode diffuse_burley, specular_schlick_ggx;
|
|
uniform sampler2D stone_map : source_color, filter_linear_mipmap_anisotropic, repeat_enable;
|
|
varying vec3 world;
|
|
varying vec3 world_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() {
|
|
world = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
|
world_normal = normalize(mat3(MODEL_MATRIX) * NORMAL);
|
|
}
|
|
void fragment() {
|
|
vec3 weights = pow(abs(world_normal), vec3(5.0));
|
|
weights /= max(dot(weights, vec3(1.0)), .0001);
|
|
vec3 p = world * .21;
|
|
vec3 stone = texture(stone_map, p.zy).rgb * weights.x + texture(stone_map, p.xz).rgb * weights.y + texture(stone_map, p.xy).rgb * weights.z;
|
|
float relief = dot(stone, vec3(.333));
|
|
float broad = noise(world * .35);
|
|
float grain = noise(world * 6.0);
|
|
float rock = COLOR.a;
|
|
vec3 soil = COLOR.rgb * mix(.84, 1.14, broad) * mix(.9, 1.07, grain);
|
|
vec3 rocky = COLOR.rgb * mix(vec3(.72), vec3(1.45), stone);
|
|
ALBEDO = mix(soil, rocky, rock);
|
|
ROUGHNESS = mix(.93, .84, rock);
|
|
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(relief) * rx + dFdy(relief) * ry;
|
|
NORMAL = normalize(abs(det) * n - sign(det) * gradient * (.006 + rock * .014));
|
|
}
|