Ocean waves simulation with Fast Fourier transform

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
some time ago i read an article about ocean wave simulation in the movie's titanic and water world by jerry tassendorf their approach has become a standard for rendering ocean surface and film and is often used even in video games it has two key components fast fourier transform and oceanographic spectra in this video i am going to walk you through the basics of this technique and its implementation in unity [Music] [Music] we start with refresher on how waves are expressed in math this is a sine function if we add time to its argument it becomes a sine wave if we multiply x by number we can control how far apart the waves maximums are in space this parameter is called wavenumber if we do the same with time we can change the period of time between two maximums of the wave at a certain point in space this number is referred to as angular frequency we can scale the wave by multiplying it by some amplitude and shift it by adding an initial phase to its argument if we add another coordinate we get a two dimensional sine wave two wave numbers constitute a wave vector it determines both direction and length of the wave ocean waves are not sine waves though motion of the real water is very complex but there are simplified solutions linear wave theory tells us that the water surface is a so called trachoidal or gerstner wave in the gerstner wave every point of the surface not only bounces up and down but moves along a circle this means that the vertical and horizontal parts of the displacement assign and cosine waves respectively with large enough amplitudes horizontal displacements can overlap creating loops so we might need to scale the horizontal part down a bit we can add together several such waves the result looks pretty interesting and is good for a stylized ocean catalyte coding has an excellent step-by-step tutorial on how to do that so go read it if you are interested but we are here for a more realistic sea the good news is that to achieve it we are going to do essentially the same thing add together a bunch of gerson waves we just need a lot of them and have a better way of choosing their parameters and fiddling with them manually this is where fast fourier transform and oceanographic spectra come into play say there are n points we want to calculate waves in for instance they could be vertices of our water plane if we also have m waves the number of operations per frame is proportional to n times m because we compute every wave in every point the thing is to get a realistic water surface we want m to be as large as possible up to the thousands but you can't calculate thousands of signs in a vertex shader the common solution to this problem is fast fourier transform there are great systems like for example crest that don't use it relying instead on such techniques as scrolling textures calculating waves in several levels of detail and others but we are going to use fft let's update our math for waves first using euler's formula if you are not familiar with it i suggest you watch this triblion brown video linked in the description with euler's formula we can replace the sines and cosines with a complex exponent we can also replace the amplitude in the initial phase with a single complex amplitude that includes both of them in this notation the displacement of the surface from the sum of waves looks like this fast fourier transform is a family of algorithms for fast calculation of discrete fourier transforms dft works just like a regular fourier transform but operates on discrete functions again check the three blue and brown video in the description if you are completely new to the topic our sum of waves happens to be dft or inverse dft to be precise if the following is true the number of points in which we want to calculate waves and the number of waves themselves are equal and coordinates of the points and wave numbers lie on regular grids with that in mind let's get back to the sum we computed in n points for n waves we can push the time dependent part of the waves into the amplitudes so they don't get in the way if we then substitute coordinates and wave numbers values into our sum the length scale cancels out this is why we wanted them to be on specific regular grids after that the sum looks like an inverse dft save some differences in summation limits the complexity of dft computed directly is n squared just like we've seen with our waves earlier fast fourier transforms calculate them in n log n time which is a huge improvement because we are going to deal with n about several thousands or even larger there are many implementations of fft on cpu out there but since we are going to use ours in a game we can expect a capable graphics card so i've implemented the two-dimensional coolituke fft in compute shaders for information on how to do this see the references in the description now we need to assign the parameters to all these waves wave vectors are determined by the special grid we choose so we will express the other parameters as the functions of them abstract mathematical waves can have any combination of wave number and frequency but in real waves these parameters are connected through a so-called dispersion relation these relations are different for different kinds of waves for example electromagnetic waves in vacuum have frequency proportional to the wave number most of the ocean waves are gravitational wind waves this means that the disturbing force acting on water is wind while restoring force is gravity for them the relation looks like this here g is gravity acceleration and h is water depth the only parameter left is complex amplitude the process of wave creation is largely random however while amplitude of any particular wave is random on average they obey some laws for example longer waves tend to have larger amplitude or waves traveling perpendicular to the wind direction are a lot smaller than the ones going along it two important types of such flaws are energy spectrum and directional spread the energy spectrum describes how big as a wave with a certain frequency it doesn't depend on the wave direction there are several spectra created by oceanographers popular in computer graphics they all have a cutoff in the low frequency zone because lower frequency means higher wavelength at a given wind speed the distribution has a maximum possible wavelengths these spectrums also have a peak wavelength at which the waves are the highest and the tail of short and frequent small waves the primary factors that determine the shape of the energy spectrum are wind speed and gravity acceleration some models also consider fetch or the length scale of the area over which the wind blows and the depths of the water the directional spread describes whether the waves tend to follow wind direction or spread around it depends primarily on the angle between the wave vector and the wind the spread also depends on the frequency of the wave so for example large waves all have pretty much the same direction as the wind while some of the small ones could be almost opposite to it the paper by christopher horvath has an overview of both energy spectrums and directional spreads following them for this project i am using the tma spectrum and hasselman's directional spread how do we get a random complex amplitude from these spectrums following the original paper by tessendorf and the paper by horvas again we will use this equation the first part is just two independent random values from normal distribution with mean zero and dispersion one the second part is the square root of our spectrum the extra stuff comes from discretization and conversion from a frequency spectrum to a wave number one this is our stationary spectrum to evolve it in time according to tessendorf we should use this equation it guarantees that the result of the fft will be a real number i should say that while these spectrums are good you still may want to modify them to match the reference or for artistic reasons for instance you could scale the whole spectrum up or down or filter out waves in a frequency band besides the waves generated by the local wind the ocean has swell swell is the waves that traveled away from the region they were created in they look quite different from the local waves they appear to be long and parallel to each other spectrums mentioned above especially directional spreads are not suitable for swell the paper by horvath gives a modification of the directional spread function which makes the waves more spell-like you can use the sum of two different spectrums one for the local win and one for this well let's step through the calculations from start to finish at startup we generate on the cpu a texture of the same size as our grid with pairs of gaussian random numbers in red and green channels after that all the mass is done on the gpu with compute shaders every time we change parameters of the ocean we have to calculate wave vectors themselves their corresponding frequencies and the stationary spectrum we pack them into the two render textures the complex amplitudes that we discussed above are for the vertical displacement of the surface but as you remember in gerstner waves there is also a horizontal movement amplitude for horizontal displacement can be computed using vertical amplitudes like this we multiply by i to change sines into cosines and by a normalized wave vector to get the correct direction of the displacement for rendering we also want normals to compute them we need the derivatives of the displacement we could estimate these derivatives from the displacement itself numerically but because the derivative and fourier transform are linear operations we can swap their order and compute the derivatives through f of t we have three displacement components and two derivatives of each of them so in total it's nine ffts but two of the derivatives are equal so there is actually only eight the results of all of them are real values by exploiting this fact we can pack them in pairs so instead of eight ffts we are only doing four finally we calculate the ffts and pack the results into the two textures one for displacement and one for derivatives we then can use these textures in a shader to displace the surface and calculate normals for lighting with that done we can render apache motion because our textures as a result of dft they are perfectly tileable on a larger scale the styling looks very ugly you could increase the size of the patch but you'll have to increase the resolution of it as well and as the resolution grows even fft becomes really expensive really fast to manage this problem we will use several fft cascades with different length scales the range of wave numbers of the cascade is determined by its length scale and resolution cascades can overlap but we want to sample spectrum at a given wave number only once so we need to cut them off the borders of the wave number the mains of the cascades are very important on the one hand you don't want small waves to end up in the coarse large cascade because it doesn't have enough spatial detail on the other hand you don't want big waves in the small cascades because this will cause very noticeable tiling the length scales of the cascades should be chosen in such a way so there are no big gaps in the spectrum coverage the nice thing about cascades is the fact that you don't need larger 50s to make the waves look good in my experience three cascades of 256 by 256 textures are enough to make pretty detailed water the calculations for one such cascade take about 0.5 milliseconds on my laptop with rtx 2060. i'm also new with compute shaders so there is probably room for optimization the last thing we are going to consider is buoyancy physics to make something flawed we want to know water height at a given point there are two problems with that first of all we have to calculate physics on the cpu while all the fft results are on the gpu simple read back from gpu memory causes a so called pipeline stall which really hurts the performance there are two alternatives the first one is to repeat the calculations on the cpu but only for displacement in the largest cascade and with reduced resolution another option which i chose is a synchronous gpu read back it can read the data from gpu without causing a pipeline install the catch is that it has several frames of delay i found out that on my machine this delay was not that bad and it worked great for buoyancy physics of relatively large objects if the delay becomes a problem you could try to schedule the displacement calculations and read back several frames in advance so when the time comes the data is ready the second problem is that we only have the displacement data and not height field if you sample the vertical component of the displacement at some point it will actually return the height from the shifted point one of the solutions to this is to sample the texture several times we first sample the displacement in our point of interest then we step from this point by an amount of its horizontal displacement backwards then we do the same in the resulting point and so on three or four iterations is enough to get a very accurate result there is of course much more to these simulations than i have talked about in the description there are links to some articles and resources i used by researching for this video and we didn't even mention ocean shading geometry and lod management which are big topics in their own right let me know in the comments if you are interested in such things the source code is as usual on github on that note thanks for watching subscribe for more and see you
Info
Channel: Jump Trajectory
Views: 154,044
Rating: undefined out of 5
Keywords: FFT Ocean, Unity Ocean Shader, Unity Water Shader, Fast Fourier Transform Ocean, TessendorfWavesUnity
Id: kGEqaX4Y4bQ
Channel Id: undefined
Length: 14min 25sec (865 seconds)
Published: Sun Dec 06 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.