How Do You Use a Shader to Create Clouds in three.js? (Part 2)

After some effort (and a lot of luck), I was finally able to create an example projecting a cloud shader on a flat plane:
example
This is a combination of the water shader in three.js examples and a shader variant at:
shader

Since the shader can be made to change the orientation of the clouds, there are a couple of ways I might deploy this:

  1. Make the flat plane larger so that it provides a full screen backdrop. I need to figure out how to change the orientation of the clouds to match the changes in the orientation of the camera.
  2. Reorient the plane so that it is a flat plane that is below the object and displays a top view of the clouds (a moving undercast).

Does this seem like a practical approach? I tried sticking the plane in my main program and there did not seem to be much of a frame rate hit (still above 55 fps).

Does anyone know how I could change the iMouse.xyzw values so that the clouds are re-oriented?

Thanks,
Phil

Your example runs with 4 FPS on my iMac (4 GHz Intel Core i7, AMD Radeon R9 M295X 4 GB) with latest Chrome :frowning_face:

Notice that not every raymarching shader you find is optimized or even has a practical use. With clouds you don’t necessary rely on sharp features so you can upscale a lot, rendering in a lower resolution. If it is practical for your case depends on various things, such as what your target platform is, what your projects target audience devices specs are in average etc.

There is always a cheaper approach too, if you look around here for example one used just billboards still giving a good result.

Ouch!

I am using a fairly powerful NVidia card. I knew that these shaders are not necessarily optimized (this shader is a variant of a shader first posted on ShaderToy). But I had no idea that there could be such a difference in shader performance on different graphics cards.

Before I got this shader to working, I was considering trying an example, where I set the plane flat and used the shader to create a moving fog-like undercast. The other example I had posted created a moving undercast using flat planes that moved under the viewer. So I was going to see if I could improve on that speed by using a stationary plane where the shader caused the pixels to move.

I am doing this for a lot of people who might not have access to the latest and greatest hardware, so 4 FPS is definitely not acceptable.

Yep, that is my program. I am just trying to see if there are ways to use shaders to improve on that performance.

Actually, I was hoping to use the shader to create clouds that are sharper. One way I was hoping to improve performance was to make it transparent, drawing pixels only where there were cloud textures, and not sky pixels.

I got solid 60 FPS on my Titan X :grin::+1:, most important optimization you should do is upscaling, you don’t need a high resolution for good looking clouds. Another thing i would generally recommend is not using a fullscreen quad, instead using bounding volumes with boxes and their backfaces.

One thought. The code I am using to animate the scene is:

function rendAll() {
requestAnimationFrame( rendAll );
uniforms.iGlobalTime.value += clock.getDelta();
[various subroutines to move the plane and the object]
if (stflag > 0) {stats.update();}
renderer.render(scene, camera);
}

Perhaps there is something in the uniforms line that is causing the program to run slower on a Mac?

There appear to be many different methods to animate the display.

The three.js ocean example uses:

function rendAll(timestamp) {
requestAnimationFrame( rendAll );
uniforms.time.value = timestamp / 1000;


The three.js lava example uses:

function render() {
var delta = 5 * clock.getDelta();
uniforms[ “time” ].value += 0.2 * delta;


The animation code I used was from another example and was just a guess.

I see that the CodePen example where I found the shader used:

function animate() {
count += 0.01;


shader.uniforms.iGlobalTime.value = count;


Perhaps if I used that, it would run faster on your machine? Does the CodePen example run faster?

Thanks.

I will have to look into the bounding volumes. Is that like a CubeMap?
Is there a good place where I can learn about that subject?

I also get a solid 60fps on my nvidia g980, chrome, win7.
The Mac/Radeon is a bit slower, but that much difference is odd.
Mugen87, Are you running this on a retina display? It resizes automatically, so the only other disparity I can think of is the resolution, a shader running at 5120x2880 would be very slow.

I am working on my Surface Pro (old but with I7) and am also getting 4 FPS. Same is true for my iPhone 6s (although that is not unexpected). I will have to check this out. One user who was getting low numbers for my sprite cloud example said he fixed the problem by changing his Chrome settings. Perhaps the subroutine to measure FPS is slowing things down.

Just to wrap this up, I thought that the 4 FPS might be significant. However, after trying various alternatives, it appears that this is the frame rate you will typically get for this shader if the GPU is not able to handle the shader and the CPU has to do the work. So, if I am going to make this available to more users, it looks like I need to work on alternatives that use smaller shaders.

This is just a expensive shader, without heavy optimization it’s going nowhere.

On iPad it runs with 2-5 fps, though the raymarching shader alone run rather good even though precision artifacts, the ocean and whatever else you use blows it up probably. Hide those and see what you get then, you still will have to optimize it, but it doesn’t fail on that.

Discussion moved from thread where it was off-topic:

[Moved from thread where it was off-topic]

The original topic is at:

As you can see, although I was getting 60fps on my PC, others were getting much much less - as was I when I switched to my MS Surface.

So that became my test. I would try ShaderToy and other examples on my MS Surface. If they did not run at a decent frame rate, there was really no point in continuing.

The example in the Book of Shaders does raise a question I hadn’t resolved which was whether it was more efficient to create a flat plane undercast (or overcast) using a shader or a flat plane as in this file:
Flat Plane Undercast

I think the flat undercast combined with the skybox gives a decent illusion of motion.

Just remember that you are free to choose how you project the texture. A flat plane is only one option among infinite others. If you make sure to generate a tiled (space-periodical) texture, you can apply it to the inside of a cylinder or a sphere, for instance. Or use a spherical projection onto a skybox, e.g. for combining distant flat clouds with nearby particle clouds.

I think that you will be able to use different approaches for different types of clouds.

For over/undercast, you can use flat planes since depth is not an issue. The design could be fairly detailed and could even involve shading as long as you orient the planes correctly. In the case of a distant plane, the challenge is to find a way to cover the whole sky. If you are dealing with a gray over/undercast, you can “fade to gray”. For isolated clouds, you probably want to find a way to decrease resolution with distance.

Clouds with depth that you fly through, including cumulus clouds, present a different challenge. For the low fluffy undercast, I used a “brute force” approach of using thousands of sprites. While this works, it seems inefficient in that you are redrawing the same pixels several times. I looked at using shaders. But it appears that, while shader designers have come up with some great formulas for generating clouds, those shaders are too big for small GPUs and the formulas take too much time to compute values for each pixel, sometimes redrawing the same pixel several times.

For fluffy isolated clouds, you might be able to use 3D modeling - combining simple shapes with fuzzy sprites on the edges or emitters. But, so far, the best approach seems to be the “old school” approach (circa 2000) of using several layers of Sprites. This is a proven technique, but a programming challenge that I have put off for another day.

But I do not claim to be an expert on this subject - from a mathematical, hardware or programming perspective. So I am likely overlooking some options and I would definitely appreciate hearing your thoughts.

I spent years designing a flight simulator back in the 1980s (and learned a lot of useful tricks). And I am a pilot (who has flown through many clouds), so I have a good sense of how things should look from the air.

1 Like