# Simple real-time 3D wind simulation

I am a 4th-year student in the apply math department. It's my final year, so I am working on my bachelor's thesis. The topic is "Real-time weather effects simulation for grassland". The huge work was done by my tutor, so the grassland simulation itself had been already implemented. Now we decided to limit the work to adding 3d wind modal and snowfall for result presentation. The snow particle system has been implemented recently, however, I've coped with problems while seeking information on how to implement real-time 3d wind field simulation.

There are plenty of quite complex articles on how to simplify real turbulence simulation, but it's too excessive for my work. On the other hand, there are quite simple 2D approaches using Perlin Noise, but I can't find something like that for the 3-dimensional scene.

Summing up, Could someone share some typical solution for my issue, or just post a good link?

Thank's a lot in advance and sorry for my poor English.

UPD Screenshot of the scene for whatever it may be worth

• Can you help us understand the goals of your simulation? Are you trying to get a physically accurate wind pattern and resulting snow accumulation, that could be used for example in understanding grassland ecosystems and modelling landscape interventions? Or are you trying to make something superficially plausible-looking, without regard for accurate predictions? The latter is a good match for what we do in games, but we often do it with no simulation of wind turbulence at all. The former is a topic you'd likely want to talk to experts in scientific computing about, as it's outside our domain. Commented Feb 13, 2021 at 22:18
• Thanks for the comment. Sure, I should have clarified that. My goal is to make something 'superficially plausible-looking, without regard for accurate predictions'. No aim to support turbulence as well, I've noticed it just because the majority of articles that I managed to find were about this one. Commented Feb 13, 2021 at 22:31
• It sounds then like you might want a particle system incorporating "curl noise," which is a cheap way to get turbulent-looking movement without actually running a fluid sim. You can art direct the turbulence by controlling the frequency and amplitude of the noise function(s) you use. Commented Feb 13, 2021 at 22:35
• At first sight, I believe that's exactly what I need.. Gonna look it up in more detail tomorrow and inform you if it is the solution. So quick response, kind of you! Commented Feb 13, 2021 at 22:43
• If you find you're able to solve your problem using that lead, be sure to post your solution as an Answer below to help future readers too. Commented Feb 13, 2021 at 22:48

I think curl noise is the right idea.

The concept of curl noise is fairly straightforward. It involves taking the derivative vector of a smooth coherent 2D noise, and rotating it 90 degrees. The result is a vector field which never converges or diverges at point, but instead flows neatly in cycles. Curl noise can be extended to 3D if you consider it relative to a 2D plane, by introducing an extra dimension to the noise, and performing the derivative rotation around the vertical axis. From there, you can evaluate a wind vector at any point, but the wind won't change direction over time. To address this, add a fourth coordinate to vary the noise through time.

If your world is flat, then assuming Y is vertical, you can just rotate the dx/dz derivative values and keep dy as it is. Your rotated derivative might become <dz, dy, -dx> or <-dz, dy, dx> depending on which direction you rotate. I'm not quite sure if this preserves the divergence-free property, but I think it will be good enough. If your world is spherical rather than flat, you'll need to do the rotation around the unit vector pointing away from the world's center, but it's the same basic idea.

When you add in the time coordinate, you will need 4D noise instead of 3D. You could use the 4D noise as it is, incrementing the W dimension ad infinitum. However, you may eventually run into precision problems as the value becomes arbitrarily large. To solve this, you can use a noise that loops in the W coordinate, and subtract the repeat period each time it is detected to be ahead of it.

You can manufacture noise that loops in one coordinate, by using 5D noise like noise(x, y, z, const1*sin(const2*t), const1*cos(const2*t)). This works, but it is probably needlessly complex. Ordinary Perlin noise that uses a permutation hash does loop in every coordinate. But, unmodified Perlin noise is characteristically ineffective at producing features that are pointed in directions other than 45 and 90 degrees. As such and as usual, I don't recommend using it. Not in its raw form at least.

I would use one of two methods for noise: Domain-rotated Perlin, or a well-implemented Simplex-type noise. Domain-rotating Perlin in a certain way allows you to hide the worst and most grid-aligned parts of the N+1 dimensional noise, from N dimensional slices. It also still allows the last coordinate to be periodic. Simplex-type noise is designed to have less visible grid bias on its own. In this 4D case, I believe it is also faster, especially when you also compute the derivatives. Then, if you apply the same domain rotation, you can make w periodic if the noise uses a periodic hash internally, as well as achieve the best possible appearance.

One final part. When the wind is far up in the atmosphere, any vertical component should produce convincing wind. However, as you get too close to the ground, it might be problematic to have wind vectors that point into the ground. If you can generate surface normals of your terrain, though, you can slightly alter the directions of the wind depending on how close you get to the ground. To find the direction the wind should blow if it were right on the ground, you could take <ground wind vector>=[<wind vector>-(<wind vector> dot <surface normal>)*<surface normal>]/(<surface normal> dot <surface normal>). The division part isn't necessary if your surface normal is already length 1, but it's more efficient to do the division than to make <surface normal> length 1 beforehand. To smoothly change to this vector, get a slide t=max(0, 1-((y-terrainHeight(x,z))/bufferDistance))^2 and compute <result wind vector>=(1-t)*<wind_vector>+t*<ground wind vector> To calculate the surface normal in the first place, you need the derivative of the terrain. To get the derivative, you can either compute it analytically by using derivative-supporting noise, or check neighboring terrain height values. Once you have the derivative, you can turn it into a surface normal using a similar process to this. In the case of a flat world, the tangent plane is just the flat XY or XZ plane.

• Here is a link to domain-rotated Perlin. For best results, use noise4_ImproveXYZ_ImproveXY if X/Y are your horizontal directions, or use noise4_ImproveXYZ_ImproveXZ if X/Z are. Use w as your time variable. It repeats at w=4096 (i.e. noise4_ImproveXYZ_...(x, y, z, w) = noise4_ImproveXYZ_...(x, y, z, w+4096*k) where k is an integer). All evaluators for the 4D noise repeat in the w coordinate at w=4096.
• Here is a link to a modified 4D implemetation of my OpenSimplex2 algorithm. I have added derivatives to it, as well as the same domain rotations. All evaluators except for "unoriented" repeat in the w coordinate after w=sqrt(20)*2048, or approx. w=9158.934435839139.

EDIT: These are both in Java, but you can port them if needed.

A bit late on this. Hope it still helps!

• Thank you for the answer. The theoretical part was quite clear, but the implementation surprised me a little bit. I will examine it in more details later, however, just for greater certainty: Did you encapsulate all logic into method noise4_ImproveXYZ_ImproveXZ(Vector4 derivatives, double x, double y, double z, double w) so that I can use just 'derivatives.xyz' output to define wind at the current point? Commented Mar 15, 2021 at 19:08
• There is rotation being performed on the noise in those evaluators, but you're right I should clarify better that it isn't the rotation needed to produce curl-like noise. The only rotations done there are to make the noise look better and to make it tile the way it does. You still need to do <-derivatives.z, derivatives.y, derivatives.x> to get curl-like noise for wind. Commented Mar 15, 2021 at 20:48