Quantcast
Channel: GameDev.net
Viewing all articles
Browse latest Browse all 17825

Understanding Gerstner Wave sharpness and normal calculation

$
0
0
Hi, I am currently working on implementing Gerstner Waves into a Unity shader based on this article. Note: All of my code is in C#, running on the CPU. I did this since it allows for much easier debugging/code inspection. After the algorithm is complete, I intend to rewrite it on the GPU in HLSL. I got this far implementing the positional part and started working on the normal part: https://imgur.com/SxSfOHE The calculated normals did not turn out so good. The following is a gif where the first half is the normals being calculated using Equation 12 in the article. The second half is using Unity's Mesh.RecalculateNormals(); method, which manually calculates the normals of each vertex by summing the weights of adjacent triangles (which I have been using to test the correctness of the algorithm, not that they would be exactly the same). https://imgur.com/aC6J8lb I realized my normals were having issues due to the wave sharpness (Q parameter in the article) being too high. Initially, I had a wave sharpness parameter for each individual wave, whereas reading the article again I realized it was a global parameter calculated for each wave as Qi = Q/(wi Ai x numWaves). I changed my sharpness to be a global value from 0-1 and have this code currently. void GerstnerWave(Vector3 i, out Vector3 p, out Vector3 n) { p = new Vector3(i.x, i.y, 0); foreach (Wave wave in waves) { float innerFunction = Vector2.Dot(wave.wavelength * wave.direction, new Vector2(i.x, i.y)) + wave.phase * Time.time; float cos = Mathf.Cos(innerFunction); float Qi = globalSteepness / (wave.wavelength * wave.amplitude * waves.Length); p.x += (Qi * wave.amplitude) * wave.direction.x * cos; p.y += (Qi * wave.amplitude) * wave.direction.y * cos; p.z += wave.amplitude * Mathf.Sin(innerFunction); } n = Vector3.zero; foreach (Wave wave in waves) { float wa = wave.wavelength * wave.amplitude; float s = Mathf.Sin(wave.wavelength * Vector2.Dot(wave.direction, p) + wave.phase * Time.time); float c = Mathf.Cos(wave.wavelength * Vector2.Dot(wave.direction, p) + wave.phase * Time.time); float Qi = globalSteepness / (wave.wavelength * wave.amplitude * waves.Length); n.x += wave.direction.x * wa * c; n.y += wave.direction.y * wa * c; n.z += Qi * wa * s; } n.x *= -1; n.y *= -1; n.z = 1 - n.z; } Where i is the input vertex position, p the output position and n the output normal. Wave is a class that holds all the wave specific values. Here is what I have using this: https://imgur.com/NaR5zXB All of the gifs so far are 5 waves with the same setting, except for the previous which has a global steepness value of 0.95. This looks a bit rough right now. I can't tell if the normals are wrong or just so many waves layered are naturally creating noise (Unity's RecalculateNormals is still much smoother). Not only that, but without individual steepness values the waves are pretty round and dull looking. To investigate, I created a simple wave system on a 10x10 plane. 4 waves moving vertically, horizontally and both diagonals. These normals turned out fine (look almost the same as the Recalculated ones with any steepness 0-1). https://imgur.com/OBb1mi2 So couple questions: Is the method of calculating normals above robust for 5+ variable sized waves. Am I doing something wrong? Having a global steepness value that is clamped from 0-1 makes the normals look correct in simple systems, but makes it difficult to get the waves to a higher sharpness value I need for the scene. Is it possible to have individual wave sharpnesses and get correct normals? I mostly just want my first gif, but with proper normals. Sorry for the massive post but have been working on this all weekend and want to figure it out! Thanks for any help, Erik Edit: Not sure why code formatting is odd, updating doesn't seem to fix it

Viewing all articles
Browse latest Browse all 17825

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>