Skip to content

Commit 751c6d9

Browse files
committed
pal5: Refine terrain
1 parent ab5008b commit 751c6d9

4 files changed

Lines changed: 696 additions & 406 deletions

File tree

radiance/radiance/src/rendering/vulkan/shaders/terrain_splat.frag

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@
33

44
// PAL5 terrain splat — fragment stage.
55
//
6-
// Blends up to four terrain textures per-texel by a weight atlas, then
7-
// applies the same dynamic Lambert lighting as `actor_lit.frag`.
6+
// Composites up to four terrain textures per-texel by a weight atlas using the
7+
// original engine's LINEAR WEIGHTED SUM (reverse-engineered from the shipped
8+
// `terra{N}.psh`): `color = Σ_i tex_i(tileUV) * weight_i`. Unused slots carry
9+
// zero weight; an overlay patch's active-layer weights sum to ~1, and an
10+
// untextured patch is full weight on slot 0 (its base ground). Then applies the
11+
// same dynamic Lambert lighting as `actor_lit.frag`.
812
//
913
// Texture bindings (set 2, `texSampler[5]`):
1014
// texSampler[0..3] = terrain-texture layers for slots 0..3 (unused slots
11-
// are padded with slot 0's texture)
15+
// are padded with the base texture; their atlas weight is
16+
// zeroed so they never blend in)
1217
// texSampler[4] = per-block weight atlas; RGBA = slots 0,1,2,3 weights
1318
//
1419
// The weight atlas is sampled with the per-block UV (`fragAtlasUV`); the
@@ -88,22 +93,21 @@ void main() {
8893
// world units).
8994
vec2 tileUV = fragWorldPos.xz * mat.uv_xform.xy;
9095

91-
// Per-texel layer weights (already normalized so active layers sum to 1).
96+
// Per-texel layer weights: r/g/b/a = overlay palette slot 0/1/2/3.
9297
vec4 w = texture(texSampler[4], fragAtlasUV);
93-
int layers = int(mat.misc.x + 0.5);
9498

95-
vec3 base = texture(texSampler[0], tileUV).rgb;
96-
vec3 col = base * w.r;
97-
if (layers > 1) col += texture(texSampler[1], tileUV).rgb * w.g;
98-
if (layers > 2) col += texture(texSampler[2], tileUV).rgb * w.b;
99-
if (layers > 3) col += texture(texSampler[3], tileUV).rgb * w.a;
100-
101-
// Guard against an all-zero weight texel (e.g. atlas seam): fall back to
102-
// the base layer so terrain never shows black.
103-
float wsum = w.r + (layers > 1 ? w.g : 0.0)
104-
+ (layers > 2 ? w.b : 0.0)
105-
+ (layers > 3 ? w.a : 0.0);
106-
if (wsum < 0.001) col = base;
99+
// Faithful to the original `terra{N}.psh` (reverse-engineered from the
100+
// shipped shaders): terrain is a LINEAR WEIGHTED SUM of the up-to-four
101+
// ground textures by the `.alp` blend weights —
102+
// color = Σ_i tex_i(tileUV) * weight_i
103+
// Unused slots carry zero weight; for an overlay patch the weights sum to
104+
// ~1 across its active layers, and an untextured patch is full weight on
105+
// slot 0 (its base ground). No dominant-base/alpha-over.
106+
vec3 t0 = texture(texSampler[0], tileUV).rgb;
107+
vec3 t1 = texture(texSampler[1], tileUV).rgb;
108+
vec3 t2 = texture(texSampler[2], tileUV).rgb;
109+
vec3 t3 = texture(texSampler[3], tileUV).rgb;
110+
vec3 col = t0 * w.r + t1 * w.g + t2 * w.b + t3 * w.a;
107111

108112
// Dynamic Lambert lighting (mirrors actor_lit.frag).
109113
vec3 N = normalize(fragNormal);

0 commit comments

Comments
 (0)