Homework 3: Volumetric Clouds with Ray Marching
Setup:
The magic happens on the shaders. The CPU only handles camera movement, static skybox rendering, and screen-size quad rendering. I have also passed the uv coordinates for the quad, as it will be helpful in casting rays.
Ray Casting:
Getting rays cast correctly is tricky because the camera's orientation must be considered. Initially, they are cast towards the plane at z=-1 (with respect to camera basis) by utilizing uv coordinates passed. To rotate the rays, a rotation matrix should be used with the camera basis as the rotated coordinate axes. Each basis vector should correspond to a column in the matrix.
Rendering Clouds:
After setting up the rays, rendering clouds is not hard. I use ray marching to obtain the volumetric clouds with a certain number of steps with a predefined step size. At each step, the point at the tip of the ray is marched by the step size, and a density is sampled at that point from the density field defined by Perlin Noise on the fly. Then, this density is used to obtain the color contribution of the cloud at that iteration. After blending the contribution of each point along the ray, the final color is obtained.
Fractal Brownian Motion (FBM):
Using Perlin Noise directly does not give impressive and detailed results. To enhance that, FBM is used. Briefly, it is layering Perlin noises of different frequencies until you get something detailed. In my implementation, I use 4 octaves; one can try out and find the optimal value for their implementation but note that noise computation is done on the fly, which is a heavy burden on the implementation and must be chosen carefully.
To have a more detailed introduction to FBM, see https://thebookofshaders.com/13/.
Lighting:
Beer's Law is used as the primary model for lighting. From the point, a sample in the density field is taken towards the light source. Then, using Beer's Law, the transmittance is computed to blend the lighting color.
Results:
Extension: Covering The Sky With Clouds
In the current implementation, the clouds are only visible inside a defined slab. When you are either below or above that concrete slab, the clouds are entirely hidden from view, giving an unnatural appearance.
To cover the entire sky with clouds, I have used the following approach:
Fog:
Rendering the far clouds gives an aliased view. Fog is a cheap solution for this kind of problem occurring in ray marching. You can see the comparison below.
You can see the results below:
The Final Results:
Step Size: 60 Step Size: 150
Note: Typically, the outcome requires gamma correction to reflect the final result accurately. However, I chose to forgo this step to convey a sense of dusk in the image.
Another Note: I recorded all of those experiments in debug mode, in release mode the performance would be higher.
Possible Improvements:
- Clouds in the sky look so sparse. I believe the Perlin Noise causes this. Mixing Worley Noise with Perlin Noise might give better results.
- FBM computation is done on the fly. This reduces the performance incredibly. Following the approach described in https://www.guerrilla-games.com/media/News/Files/The-Real-time-Volumetric-Cloudscapes-of-Horizon-Zero-Dawn.pdf might improve the performance.




Comments
Post a Comment