mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-08-01 18:29:24 -04:00
fix(water): stabilise the shoreline masks, and add edge foam and spray
The hard tile-like edges came from the depth the shoreline masks were built on. verticalDepth is sampled through the refraction offset, which wanders with the wave normal, and close to the beach that sample lands on dry ground — so the depth it reports collapses to nothing along wandering lines and every threshold keyed on it stepped hard. The masks now use a depth sampled straight down the pixel; the refraction colour keeps the offset sample, which is the only place it belongs. Foam was also being removed exactly where it should be strongest: a smoothstep zeroed it below 0.1 of depth, which is the waterline itself. That ramp now runs to 0.025, enough to keep the water mesh's own boundary from reading as a hard line and no more. The wet band's alpha gets the same short ramp for the same reason. And there was no spray. A sparse, much finer field now throws off the front while it is advancing, which is what distinguishes breaking water from a wet line.
This commit is contained in:
@@ -271,6 +271,15 @@ void main() {
|
||||
float verticalFactor = abs(viewDir.z); // 1.0 looking straight down, ~0 at grazing
|
||||
float verticalDepth = depthDiff * max(verticalFactor, 0.05);
|
||||
|
||||
// Shoreline masks use depth sampled straight down the pixel rather than
|
||||
// through the refraction offset. The refracted sample wanders with the wave
|
||||
// normal, and near the beach it lands on dry ground, so the depth it reports
|
||||
// collapses to nothing along wandering lines — which is where the foam and
|
||||
// wet sand were picking up hard tile-like edges. The refraction colour still
|
||||
// uses the offset sample; only the masks need a depth that stays put.
|
||||
float shoreLinDepth = linearizeDepth(texture(SceneDepth, screenUV).r, near, far);
|
||||
float shoreDepth = max(shoreLinDepth - waterLinDepth, 0.0) * max(verticalFactor, 0.05);
|
||||
|
||||
// ============================================================
|
||||
// Beer-Lambert absorption
|
||||
// ============================================================
|
||||
@@ -336,14 +345,14 @@ void main() {
|
||||
float swashPhase = sin(time * 0.55 + noiseValue(FragPos.xy * 0.12) * 6.28);
|
||||
float swashDepth = 0.30 + 0.18 * swashPhase;
|
||||
|
||||
float wetBand = 1.0 - smoothstep(0.0, 0.70, verticalDepth);
|
||||
float shallowBand = 1.0 - smoothstep(0.0, 2.20, verticalDepth);
|
||||
float wetBand = 1.0 - smoothstep(0.0, 0.70, shoreDepth);
|
||||
float shallowBand = 1.0 - smoothstep(0.0, 2.20, shoreDepth);
|
||||
// How thoroughly the surf currently covers this point. Sand deeper than the
|
||||
// front is under the run-up and soaked; sand shallower has just been
|
||||
// uncovered and is draining, so it lightens as the water pulls back. Keying
|
||||
// the darkening on depth alone left the wet zone fixed while the water
|
||||
// visibly moved over it.
|
||||
float coveredness = smoothstep(swashDepth - 0.12, swashDepth + 0.08, verticalDepth);
|
||||
float coveredness = smoothstep(swashDepth - 0.12, swashDepth + 0.08, shoreDepth);
|
||||
if (basicType < 1.5 && shallowBand > 0.001) {
|
||||
float sediment = noiseValue(FragPos.xy * 1.6 + time * vec2(0.10, 0.06)) * 0.6
|
||||
+ noiseValue(FragPos.xy * 3.4 - time * vec2(0.07, 0.13)) * 0.4;
|
||||
@@ -429,8 +438,8 @@ void main() {
|
||||
// Only on terrain water (waveAmp > 0); WMO water (canals, indoor)
|
||||
// has waveAmp == 0 and should not show shoreline interaction.
|
||||
// ============================================================
|
||||
if (basicType < 1.5 && verticalDepth > 0.01 && push.waveAmp > 0.0) {
|
||||
float foamDepthMask = 1.0 - smoothstep(0.0, 1.8, verticalDepth);
|
||||
if (basicType < 1.5 && shoreDepth > 0.001 && push.waveAmp > 0.0) {
|
||||
float foamDepthMask = 1.0 - smoothstep(0.0, 1.8, shoreDepth);
|
||||
|
||||
// Foam rides on the water rather than sitting in world space. The surf
|
||||
// carries it up the beach and drags it back, so the whole pattern is
|
||||
@@ -478,11 +487,24 @@ void main() {
|
||||
|
||||
// The surf line itself, on the contour computed above with the wet sand,
|
||||
// so the foam sits exactly where the water currently reaches.
|
||||
float swashBand = 1.0 - smoothstep(0.0, 0.17, abs(verticalDepth - swashDepth));
|
||||
float swashBand = 1.0 - smoothstep(0.0, 0.17, abs(shoreDepth - swashDepth));
|
||||
float swashTexture = 0.55 + 0.45 * cellularFoam(rot1 * foamUV * 8.6 + time * vec2(0.05, 0.12));
|
||||
foam += swashBand * swashTexture * 0.55 * foamDepthMask;
|
||||
|
||||
foam *= smoothstep(0.0, 0.1, verticalDepth);
|
||||
// Spray thrown off the front as it runs up: much finer than the foam,
|
||||
// sparse, and only while the surf is advancing. It is what sells the
|
||||
// edge as breaking water rather than a wet line.
|
||||
float sprayMask = 1.0 - smoothstep(0.0, 0.11, abs(shoreDepth - swashDepth + 0.04));
|
||||
float sprayCells = cellularFoam(rot2 * (foamUV + swashAdvect * 0.5) * 96.0
|
||||
+ time * vec2(0.6, -0.45));
|
||||
float spray = (1.0 - smoothstep(0.0, 0.035, sprayCells))
|
||||
* sprayMask * max(swashPhase, 0.0) * 0.7;
|
||||
foam += spray * foamDepthMask;
|
||||
|
||||
// Only enough of a ramp to keep the water mesh's own boundary from
|
||||
// showing as a hard line. The old 0.1 cut removed the foam exactly where
|
||||
// the water meets the sand, which is where it belongs.
|
||||
foam *= smoothstep(0.0, 0.025, shoreDepth);
|
||||
foam = clamp(foam, 0.0, 0.85);
|
||||
// Bluer foam tint instead of near-white
|
||||
color = mix(color, vec3(0.78, 0.85, 0.92), foam * 0.75);
|
||||
@@ -514,7 +536,7 @@ void main() {
|
||||
// Wet sand is a band on the beach, not a film of water, so it needs enough
|
||||
// presence to darken what is under it; foam has to be close to opaque or it
|
||||
// does not read at all.
|
||||
alpha = max(alpha, wetBand * 0.42);
|
||||
alpha = max(alpha, wetBand * 0.42 * smoothstep(0.0, 0.05, shoreDepth));
|
||||
alpha = max(alpha, shorelineFoam * 0.90);
|
||||
// Dissolve the sheet before the water geometry runs out, so the ocean fades
|
||||
// into the horizon haze instead of ending on a hard line. This has to come
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user