iFFT Ocean Wave Generator Module

I have updated my webpage to include this page that showcases the updated LAB (Li-Albert-Bouny) iFFT ocean wave generator. I have packaged the wave generator as a module that you can download and, hopefully, use in your three.js programs. Instructions are given on the page.

Ocean waves from the movie “Dunkirk” compared to waves created by this module.


I do not yet use node.js (or similar software), so let me know if I need to make any changes to the module to make it compatible with those programs.

Note that the zip file includes a sample program that contains the module internally so that you can run the program locally and experiment with making changes and improvements to the module and settings.


I have now added a new page from which you can download the version of the GrdMap module (GrdWtr) that works with the Ocean module to provide you with a moving map of animated waves that extends to the horizon… As above, the zip file includes a sample program that contains both modules internally, so you can run the program locally and experiment with changes and improvements.

UPDATE 5/31/2023
The “GrdMap and GrdWtr” page listed above has been updated. The GrdWtr module is now a simplified version of the GrdMap module designed to work with the Oceans module. The GrdMap module allows you to add and modify textures and materials. This requires the addition of a couple of functions to your main program. Both modules fix the “wrapping” problem discussed and solved below. The Oceans module has not been changed.


The waves look quite realistic. Thanks for providing the code as a library/module.

Do you plan to make a generator for beach waves? They have different shape when they break on the beach, not just “chaotic” ripples.

1 Like

That would be an interesting challenge and there is definitely room to improve the module.

However, for now, I plan to continue to work on my flight simulation modules, including adding some form of enemy AI-driven aircraft. And, now that I know how easily the terrain can be reshaped, I might work on a module to create terrain using height maps.


NIce! Thanks for sharing this. And it responds to directional lights in the scene. :+1:

That’s funny. You made the ocean and now you want to make the land. I made the land and now I want to make the ocean :smile:
But I didn’t find it that easy with the landmasses. I messed around there for two years. But now I can fly around freely or walk around on the surface. I’ve had an AMD 7900XTX readon for about 3 weeks and it runs so smoothly even when I’m flying very fast.

I now use almost 1000 maps only for the earth. I have far better ones but they don’t have space on my tablet. Clouds and the ocean are now the next big steps. That’s why I find your post very interesting.
A planet-wide ocean will be a challenging task. Because of the curvature I will need a lot of dynamic reflection renderings. To connect that with a dynamic surface, which has to adjust its resolution depending on where you are, will certainly also be a mammoth task. But it would be boring otherwise. At first i will analyze your recommendation with the ifft wave generator in detail. Thank you for the tipp :+1:

1 Like

iFFT seems to be the recommended approach for creating ocean waves. More modern examples seems to take a slightly different approach to generating the waves, but this program seems pretty fast. (It even runs at 60 fps on my iPhone.)

You may want to add some kind of cascading to avoid tiling. However, that may not be as big a problem as I once thought. I recently realized that my altitude scale was wrong. When I fixed that, the waves started disappearing a lot faster with increases in altitude. This helped make the tiling less obvious. However, the reason is that the ocean surface was quickly becoming a featureless blue. I checked some pictures taken from the air and this appears to be true in real life.

So you may want to add some texturing to the material to create interesting color patterns in the ocean surface. Otherwise, you will be flying over a single blue color plane. Realistic, perhaps, but boring.

Yes, I need to take another shot at creating halfway decent clouds. One of the fun parts of flying on instruments IRL was being able to pop in and out of fluffy clouds. Popping out of a big fluffy cloud into the clear air was especially fun as it often gave the same sensation as stepping off the end of a cliff.

Maybe that will help you with your clouds. I uploaded this to github because I had a problem there. I took out a lot because otherwise it would have been way too big, but what’s still in there are my cloud texture generators Cloud and Worley in cloud-model.js

In the shader I had the problem that my weathermap, which determines where clouds are, caused ugly borders. I was able to solve the problem with a higher threshold value. For the actual cloud effect, however, the cloud generators are important. Cloud and Worley are two 3D textures.

Here is a screenshot in reddish light. Flying through there looks pretty good. Like through dense fog. But I’m not satisfied yet and am still working on it myself.

1 Like

If i find the time i will make you a small sample app with my clouds and upload it to github

Thanks! I had some luck creating flat cloud layers using thousands of sprites. I looks like you may also be using sprites, but to create fluffy clouds instead.

BTW - do you know if displacement maps in three.js materials work on all 3 axes (vector displacement) or only on the vertical axis? The iFFT method computes displacement on all 3 axes - which is why the displacement map shown in the upper left panel on my demo program is multi-colored. And the related normal map is computed assuming that there is 3-way displacement.

I don’t use sprites. These are volumetric clouds where you can really be inside. To do this, I define a volume in which clouds should be and then I perform raymarching. I integrate numerically the variable cloud density that depends from my cloudgenerators step by step along the ray. In addition, the density decreases with altitude, which is why the clouds below are flatter, wider and more dense , just like in reality. As a result, I get really dense, hazy clouds, because I create quasi-physical clouds. Quasi-physical because I have to integrate numerically and cannot take infinitesimal small steps. That would be far too computationally intensive. The disadvantage of my method, which creates realistic clouds, is that it is also quite computationally intensive. At least for mobile devices. But if you take smaller volumes (just 10 km instead 1000 km) and don’t make the integration steps too big, it works quite well. The picture is from my tablet. My readon 7900XTX on the desktop has no trouble at all and creates very nice clouds over tousans of km because I can place the integration steps very high there. I’ll make you a cloud app at the weekend. As mentioned, I’m far from finished, but it will help you to understand how it works. Since I have overcome the actual hurdles with the clouds and know that the rest is just fine-tuning and optimization, I have dedicated myself to the numerous other unsolved tasks of my project. I have to do cloud shadows too

1 Like

I will be interested to see if my computer can handle both iFFT waves and raymarching clouds. Above a certain altitude, I can dispense with the displacement map and switch to using a flat plane with normal map. And you should not have to render a fully detailed cloud until you get close to one. (And once you get inside the cloud, everything is white - and you hope it stays that way.) So it might be possible to economize enough to keep the framerate at my target of 60 fps.

I’ve even extracted the clouds into a miniapp. I’ll clean that a bit and then upload it.
The idea of ​​making the clouds only in the close-up range as volumetric clouds also occurred to me. It works well from the ground, because the atmosphere only allows a maximum visibility of about 300 km anyway, and that under the best conditions and you can no longer see any cloud details much earlier. But the atmosphere is important for a realistic impression! Because it changes the appearance of the clouds significantly after just a few km. That’s why I also have a scattering atmosphere, i.e. my atmosphere is also volumetric. You can see them well in my screenshots above. Or here in my homepage:


Without an atmosphere, the clouds appear too dominant in the sky when viewed from the surface. The atmosphere scatters light more and more with distance and prefers blue light. My challenge is that clouds can be seen much further very clearly from space, but that’s my handicap, not yours :grin:


Fluffy cumulus clouds are definitely the most challenging. You can handle stratus clouds with a simple flat plane. And I had some luck creating a fluffy undercast with sprites (I will see if I can resurrect that demo.)

If you are going to be flying at supersonic speeds, you can probably focus mostly on the distant and mid-range design. The simulations I am working on are subsonic, so I need to focus on nearby and mid-range design. I might not even reach the more distant clouds.

Here the link

I have tried to omit everything that has nothing to do with clouds. I added a sphere so you have an example of how the clouds cover something or are covered by it. The ugly ripples at the edge of the clouds and where there is only a hint of clouds comes from my primitive raymarching.

I still have a few things to improve on.

If you have any questions, just ask, because fighting through it yourself can be tedious.

P.S. I’m making progress on my ocean. I’m excited to see what I can achieve over the weekend.

1 Like

Thanks. It sounds like this could be really helpful.

Regarding the ocean, I find that I am facing a problem that I thought I had solved. The flat surface which holds the ocean consists of 3 groups of squares of increasingly larger sizes. I want the squares to use the same animated normal texture to create an animated material, but, in all cases, the texture needs to appear to be the same size. For example, if I have two squares and one is 2X larger than the first, that second square needs to show the animated material 4X.

Here is an example: On the left are 4 identical squares that each show the animated material 1X. On the right is a single square that is 2X larger. It also shows the material 1X, but needs to show the animated material 4X so that it looks identical to the 4 squares on the left.

The simple solution would be for the larger square to repeat the material 2X in each direction. However, in Three.js, the repeating is done at the texture level. So repeating the texture causes the material to repeat on both the large and small squares.

Are you aware of a solution to this problem?

this was supposed to be solved with texture.source thing - when you have different textures with the same source (image) you can have different uv repeat settings on them

1 Like

Thanks for the heads-up. I will see if I can find some examples using that approach.
That sounds a lot easier than the other option I was pursuing of having to create a BufferGeometry with segments and pushing the same material into each segment. (They have gotten rid of faces, so all those old discussions were useless.)

Here is what I am trying with no luck:

let txtB = txtA.clone();   // txtA is the original texture
txtB.source = txtA.source;   // with cloning, this may be unnecessary
txtB.wrapS = txtB.wrapT = THREE.RepeatWrapping;
txtB.needsUpdate = true;

All I get as a result is a black texture and an error message that:
“Failed to execute ‘texSubImage2D’ on ‘WebGL2RenderingContext’: Overload resolution failed.”
The txtA is created as a frameBuffer.texture, if that makes any difference.

With the BufferGeometry is my approach. Unfortunately, I still haven’t understand the problem why my DataTexture suddenly turns black from a certain geometry resolution. And in addition this issue is also device-dependent, very strange. With BufferGeometries it would be possible to create a tiling free ocean with high resolution in close areas and low resolution from far areas.

It appears that I will have to try this method.
Could your problem with black texture be that the texture is somehow not a multiple of 2?
I think that is a requirement for DataTexture. Or maybe I am thinking of MipMaps.

try harder :sweat_smile:

oh I did not try that tbh. Idk why would it not work, but maybe. make a fiddle. you were right, it does not work.

1 Like