Skip to content

Allow waves to change direction seamlessly - #42

Closed
TheDan64 wants to merge 2 commits into
Neopallium:mainfrom
TheDan64:wave-dir
Closed

TheDan64 wants to merge 2 commits into
Neopallium:mainfrom
TheDan64:wave-dir

Conversation

@TheDan64

Copy link
Copy Markdown
Contributor

Implements part of #2 - change wave direction. I'm not sure the waves look 100% identical to before, but they're still pretty close to my eyes..

Note that there are two extra commits from #41 since I needed some update code from there so I based it on that PR. So that one should be reviewed + merged prior to this.

Comment thread assets/shaders/water_functions.wgsl Outdated
Comment on lines +64 to +73
// Sample both wave directions independently
let wave_a = sample_directional_wave(p, time, material.wave_dir_a);
let wave_b = sample_directional_wave(p, time, material.wave_dir_b);

// Asymmetric smoothstep - old waves fade out faster than new waves fade in
// This mimics how energy dissipates faster than it builds, looking more natural
let blend = smoothstep(0.0, 0.85, material.wave_blend);

// Blend wave patterns - NOT rotating, just fading between independent patterns
let d = mix(wave_a, wave_b, blend);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to blend the wave directions (A, B) on the CPU instead of here. Also the Rust wave_height code doesn't do the same blending of sampled waves as this, which would cause "boat physics" to be wrong.

Calling sample_directional_wave multiple times increases the cost of the shader, which is a problem for some mobile/lower powered GPUs. That is the reason for the QUALITY_* defs.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this blending must be done in the shader, then #ifdef should be used to enable/disable the extra sampling based on the wave_blend value. You can look at how the QUALITY_... defs are done.

Suggested change
// Sample both wave directions independently
let wave_a = sample_directional_wave(p, time, material.wave_dir_a);
let wave_b = sample_directional_wave(p, time, material.wave_dir_b);
// Asymmetric smoothstep - old waves fade out faster than new waves fade in
// This mimics how energy dissipates faster than it builds, looking more natural
let blend = smoothstep(0.0, 0.85, material.wave_blend);
// Blend wave patterns - NOT rotating, just fading between independent patterns
let d = mix(wave_a, wave_b, blend);
#ifdef BLEND_WAVE_DIRECTION
// Sample both wave directions independently
let wave_a = sample_directional_wave(p, time, material.wave_dir_a);
let wave_b = sample_directional_wave(p, time, material.wave_dir_b);
// Asymmetric smoothstep - old waves fade out faster than new waves fade in
// This mimics how energy dissipates faster than it builds, looking more natural
let blend = smoothstep(0.0, 0.85, material.wave_blend);
// Blend wave patterns - NOT rotating, just fading between independent patterns
let d = mix(wave_a, wave_b, blend);
#else
let d = sample_directional_wave(p, time, material.wave_dir_a);
#endif

Also could you add an example that showcases wave blending.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking the blending must be done in the shader? Namely because it does a crossfade to make the transition look smooth and natural. Without it, it looks like the whole sea is just rotating in place. And I'm not sure that could be done on the CPU

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wonder if the wave_blend should be a vertex attribute, this would allow having a transition region between two different wave directions (currents). As a vertex attribute the GPU would smooth the blend value across the water tile.

@Neopallium

Copy link
Copy Markdown
Owner

@TheDan64 I fix an issue with the water quality (it was badly broken for awhile) and rebased your PR here #43 .

Comment thread src/water.rs
Comment on lines +71 to +73
// Snapshot current blended state as "old" direction
self.dir_a = self.current_blended();
self.dir_b = normalized;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that this will cause a "jump" in the water direction when done during an active blend. I had tried to fix it, but then realized that snapshotting the current blend is going reset the water to the direction it was "blending" between, but without the blending. So that causes the water to visually "jump".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I've been trying to figure out where that jump came from... I'll close this PR in favor of yours then

@TheDan64 TheDan64 closed this Jan 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants