Outerra forum
Outerra Engine => Technology => Topic started by: Aekold on November 22, 2011, 07:44:45 am

Which technology do you use for the foam rendering? Do you have any ideas how to make breaking waves?

Foam is just a moving texture applied to areas with steep slope, with rising probability as the water gets closer to a shore. Geometry of waves is rather simple at the moment, it's basically a heightfield without overhangs, it only makes an illusion of breaking wave. Full breaking waves would need to be modeled better, or the front part would have to be modeled as an addition to the existing water shape.

You wrote that you store the wave profile for different skew factors. Do I understand correctly that this is an array of 1D periodic functions?
If yes, how you then convert it to the 2D height function when you need to create a shore wave depending on the distance field value?

Yes, it's an array of 1D functions, but stored as a 2D texture, so that it's interpolated when you perform a lookup to it using the wave position and skew factor. So for the given point you compute the current position within the wave sample, and its skew factor (from distance to shore and depth, and current time). This creates waves moving synchronously towards the shore, with changing front as they near the land. To break up the artificial synchronous rhytm there's another random map generated, that's also changing over time, that basically controls selection from multiple such waves (each with a slightly different period, wave speed etc) coherently for continuous 1020m regions.

Thanks!
I try to experiment with the skewed trochoidals  what is the sensible range for parameters b and gamma?

i. e., which parameters were used to generate the wave profile here:
http://1.bp.blogspot.com/JgtSygJ9i0k/TV13w2tPXUI/AAAAAAAAAFw/T77xJGYLuC4/s1600/trochoid2.gif (http://1.bp.blogspot.com/JgtSygJ9i0k/TV13w2tPXUI/AAAAAAAAAFw/T77xJGYLuC4/s1600/trochoid2.gif)
?

I used Microsoft Mathematics (http://www.microsoft.com/education/ww/products/Pages/mathematics4.0.aspx) to visualize and tune the waves, with this equation:
show2d(plotparam2d(t0.05sin(2pi(tfloor(t))^0.4),0.25cos(2pi(tfloor(t))^0.4),{t, 0, 10},{x, 0, 10},{y, 1, 1}),{x, 0, 10},{y, 1, 1})
b should be something small, like the 0.05 there, to avoid overhangs. Gamma 0..1
You can toy with the parameters there, to see how it looks.

Thanks a lot again!
I am sketching in Wolfram and it looks very similar:
http://www.wolframalpha.com/input/?i=parametric+plot+%28t0.05sin%282pi+frac%28t%29^0.5%29%2C0.25cos%282pi+frac%28t%29^0.5%29%29+t+from+0+to+1 (http://www.wolframalpha.com/input/?i=parametric+plot+%28t0.05sin%282pi+frac%28t%29^0.5%29%2C0.25cos%282pi+frac%28t%29^0.5%29%29+t+from+0+to+1)

Yes, I would use Wolfram today :)

How do you keep the computational time reasonable? Do you calculate only those shore waves inside a frustum? If yes, are they all synchronized so an observer can rotate his head forth and back and see a correctly travelled (while an observer was not seeing it => it was not processed) wave?

One more question: do you increase a frequency as a wave approaches a shore?

The shore waves are only computed for tiles that actually touch the shore. Open sea waves are always computed, and then superimposed over the beach waves.
The wave computation is stateless  the wave height only depends on the current time, distance to shore and water depth, but not on the previous values of height or the neighboring points. A full simulation would be too heavy.
Increasing the frequency with shortening distance  would be possible, but it may introduce a shear effect. Variables that continuously change can have various ugly effects with this approach, for example the gradient map must be sampled in a discrete manner when used for foam rendering, otherwise the apparent foam movement will have wild directions. Took me a while to figure out, too.

Interesting to notice, thanks!
Let me clarify one point.
Say you have a large island with a very long shoreline  will you generate all the shore waves on the tiles, touching the shores or only for the visible tiles?

I also wonder how you resolve an issue when a shore wave meets the shoreline. I've got a problem that it 'disconnects' from the ocean and continues running through the beach. On youtube videos from Outerra I've seen that this does not happens there, so it creates a nice surf effect. How do you achieve this?

Interesting to notice, thanks!
Let me clarify one point.
Say you have a large island with a very long shoreline  will you generate all the shore waves on the tiles, touching the shores or only for the visible tiles?
Only the visible ones. Or better said, only the visible ones that need the level of detail.
I also wonder how you resolve an issue when a shore wave meets the shoreline. I've got a problem that it 'disconnects' from the ocean and continues running through the beach. On youtube videos from Outerra I've seen that this does not happens there, so it creates a nice surf effect. How do you achieve this?
Two things  tuning the slope of the trailing part of the wave, so that it's lower than some average shore steepness, and attenuating the wave when it goes inland. The issue still occasionally appears here and there though.

Thank you for your detailed answers!
How do you calculate foam factor (how much foam you should render) near the shore? Do you use world depth or screenspace depth?
If first, how do you pass to to the GPU and how to you store it, if second, how do you avoid different foam factors at different view angles as it is here:
http://www.youtube.com/watch?feature=player_detailpage&v=UMHgBplll8Q#t=202s (http://www.youtube.com/watch?feature=player_detailpage&v=UMHgBplll8Q#t=202s)
(watch from 3:22)
?

Hmm, I'm simply using the distance map to shore to determine the static foam factor, combining it with dynamic foam strength value stored as the second channel in the wave profile texture.

How do you define the shape of the wave? Is it deformed by the distance field or is the center of the wave always ahead of the side parts?

I'm not sure what you mean here. The distance determines the shape, as it serves as the second coordinate into the trochoid shape texture.

I mean not the profile, but the shape of the wave front (i.e., projection of the wave of the ocean plane).

Um, maybe I didn't explain myself clearly. Let me describe the process again:
 water geometry comes in the form of quadtree meshes, same as terrain, except it's all on sea level
 vertex shader takes the coordinates of current vertex and looks up the distance to shore in the distance map
 using this distance, current time, current sea depth and some timing constants it fetches the wave height from the trochoid texture, as I described earlier
 the obtained height is subjected to some filtering, attenuation if it's inland etc, and it's used to displace the input seaplane coordinates in the direction of the normal vector
That's essentially all there is. The waves appear as the result of this algorithm.

So, the wave is not a separate object, right?
How do you achieve then that the waves appear separately, not in a continuous front?

No, it's not a separate object. I wrote about why they appear separately earlier here:
... for the given point you compute the current position within the wave sample, and its skew factor (from distance to shore and depth, and current time). This creates waves moving synchronously towards the shore, with changing front as they near the land. To break up the artificial synchronous rhythm there's another random map generated, that's also changing over time, that basically controls selection from multiple such waves (each with a slightly different period, wave speed etc) coherently for continuous 1020m regions.
It's the second map that creates batches of waves out of the uniform waves concentric around the shores (conshoric waves? :D), that smoothly emerge and then vanish, being randomly replaced by another batch with a different phase and slightly different frequency and wave speed.
I should really write a paper about it :)

Thanks for your patience!
I should really write a paper about it
Well, that would be super great! I would volunteer to review it then :)

It's the second map that creates batches of waves out of the uniform waves concentric around the shores (conshoric waves? :D), that smoothly emerge and then vanish, being randomly replaced by another batch with a different phase and slightly different frequency and wave speed.
Could you please give some more hints about this batch map, how to create and animate it?
Some more formulas on that would be really valuable :)

The goal is simple, to generate a tileable map that contains values used for wave selection and modulation. I'm generating a few random positions in the map, together with the values for peak width and amplitude. Using the position, width and amplitude, the peaks are rendered into the texture (or, rather, a contribution of each peak is accumulated for each pixel) using the following equation:
dx = x  xp;
dy = y  yp;
h = A*exp((dx*dx + dy*dy)/W) (http://www.wolframalpha.com/input/?i=plot+0.2+exp%28%28x*x%2By*y%29*10%29%2C+x%3D1..1%2C+y%3D1..1)
(It's not cut, I don't know how to set the zrange in Wolfram Alpha)
Since it's just a single channel, I'm using positive/negative amplitudes to select from two wave functions, giving appearance of multiple nonuniform waves.
The amplitudes are also animated  when a peak is generated, it's amplitude is initially set to 0, slowly changing to the desired amplitude over time and then back to zero. Once it reaches zero, another set of parameters is generated.

Huh, so simple :) Thanks!
I was trying to paraemterize the wave along the wavefront  that's a devil)

Tried that one too, no way :)
It's impossible to get the second coordinate (along the contour, the first one being the shore distance). Nothing that would be continuous and universal.

Well, if the islands, generating shore waves, are well away enough, you could.
You can put the circle center in the middle and stretch it from inside until it hits the shoreline. Then you can use original angular coord from the circle to parameterize the shoreline. You can then normalize it by calculating the shoreline perimeter and adjusting coords according to real distance (so they are not overstretched or overshrinked due to relief). Then you can continue dilating it radially to spread the same coords to the shore waters.
Should work even if the island is not convex.

Do you modify the wave's frequency dependant on depth/distance in the point? Or do you modify only the amplitude? If yes, how?
I've got an issue with a wave, disconnecting from ocean.

Can you show it?
The frequency is constant, distance affects only the phase. Amplitude is modulated on both ends  on large distances from shore it starts slowly from zero, and then once on the land it falls back to zero more quickly. The constants are specific to the sizes of our tiles.

(http://img683.imageshack.us/img683/2432/disconnectingwave.png)
I've colorcoded wave height with red, so you can see it distinctly. The 'disconnected' wave is circled with blue.
The effect appears mostly when the shore is very gentle.

I see, yes it's a problem with gentle slopes. Did you try to attenuate it with the distance inland? I've got this voodoo for it there:
amp *= saturate((0.6w)*10);
With w being the signed distance to shore, >0 on land, <0 on water.

Yes, I tried different attenuations.
I am currently using exponent, but, perhaps, will switch to your magic instead and experiment with some parameters :)

It still doesn't solve all the cases. The problem is the slope, but I'm thinking that something could be done about it. Once inland, the skew could be computed so that the trailing part of the wave matches the slope of the shore, or interpolates towards it. Together with the attenuation it would mean that as long as the peak is above terrain, the trailing part is too.

Might work! Please, let me know if you find something

I've got one more question about wave shape. Do you render waves which cannot be described as a height function y = f(x)? E.g., when gamma is 0.5, for x = 0 there two y values of the curve. How do you handle this? Or you just use gamma values when for any x there is only single y = f(x) value?

I limited the function parameters to ones where the function is not multivalued, as it would cause graphical glitches anyway. Else, I'm generating the profiles at startup using NewtonRhapson method, that will end up in one of the solutions, depending on the initial conditions, and thus it would not be welldefined.

Hi,
The shore wave and foam is great, Would you give some details(maybe some shader code) for the shore foam which looks really realistic.：）
I had tried the shore wave and get the basic shore wave workable, but they are continue all around the shore, I notice you use another texture to avoid this, would give some information of this(What the texture should be, how does change with time?)
Thank you very much.

First, there are two separate shore wave frequencies, and the one to use at given place is selected using a helper texture that contains islands of values from 1 to 1, but usually its 0.
This texture that breaks the continuous shore waves is generated procedurally, and is made of a bunch of randomly generated circular gaussian peaks which are initially generated (position, size, positive or negative amplitude), and then rendered into the texture over their lifetime, growing from 0 to peak amplitude and back. After the peak falls back to zero, new peak parameters are generated and the peak starts appearing somewhere else. These peaks correspond to the shore waves appearing and disappearing
Pixels in the texture are rendered using the following equation:
float v=0;
for each active peak:
//this is to make it seamless
vec2 p = abs(texcoords  peak_coords);
p = min(p, abs(p1));
float d = dot(p, p);
v += amp * exp2(d*inv_peak_size);

Thanks for your kindly reply.
Now, I basically understood how to break continue shore wave, still some thing need to confirm.
The procedure is tiled for the whole terrain? How to solve peaks overlap?(Use alpha blend?)
For the foam in attachment(I don't know how to insert an image, sorry) would give some detail, it's really beautiful.(Some shader code and related texture).
Thanks a lot.

Yes it's tiled for the whole terrain, it does not have any information that's terrain specific  it's just a mask that breaks the surf waves.
Our foam textures can be found in textures/terrain folder, it either applies to wave peaks or to water close to the shore, nothing special shaderwise.

Thanks a lot. :)
I'll have a try. I still have 2 quaestions:
1.Where was the gradient of distance map used?
2.For the shore wave it's normal is different from ambient wave, is some special operations to solve this?

1.Where was the gradient of distance map used?
In the lookup into the foam textures, which are animated in the direction of the shore. The coordinates are computed as C*time*gradient + static tile coordinates.
2.For the shore wave it's normal is different from ambient wave, is some special operations to solve this?
Not sure what you mean here; the surf waves are skewing towards the shore as described on the blog (http://outerra.blogspot.sk/2011/02/oceanrendering.html), which is done using the distancetoshore map.

Quote
2.For the shore wave it's normal is different from ambient wave, is some special operations to solve this?
Not sure what you mean here; the surf waves are skewing towards the shore as described on the blog, which is done using the distancetoshore map.
I mean there is an ambient wave, for the shore it's another wave, each wave have different normal, how do you solve this?

2.For the shore wave its normal is different from ambient wave, is some special operations to solve this?
Aha, that "it's normal" confused me :)
Normals are computed dynamically from partial derivatives of both types of waves, which are computed algorithmically.