(For better understand this article I suggest you to read GPU Gem2 Chapter16 first)
Since the GPU Gem2 released, there are a lot of discusses about Sean O’Neil ‘s paper Chapter 16. Accurate Atmospheric Scattering and also lots of practice to try to implement it in different projects (Unreal, Unity3D…) .
That is a really good paper to describe simplified equations and explains how to implement a real-time atmospheric scattering algorithm entirely on GPU and gave examples.
Although it works good in GPU, there is one significant limited on this implementation (based sample in Gem2) is that the atmosphere height should be always 2.5% of the planet’s radius and the scale height need to be 25% of the atmosphere’s thickness (earth like). The radius of the planet doesn’t matter as long as those two values stay the same.
It is because the scale function which approximate scattering lookup table is created based on that atmosphere thickness and the planet’s radius. One scale function cannot achieve an correct result for all of atmosphere height, you need to calculate a new scale function for different radius ratio of atmosphere/planet.
Since Sean O’Neil get this scale function by Graphical analysis software based on scattering integral lookup table, it can not be got easily and automatically. For a lot of people it is nearly impossible. So that is why almost all of implementation are limited by 2.5% atmosphere height ratio. I saw a lot of other algorithms to make similar result on flexible atmosphere height, like “Real Time Atmosphere Rendering for the Space Simulators” , “Planet Shader” and “Simple Flexibile Atmosphere Shaders“, all of these implementation are great experiment for flexible atmosphere but no one is based physical and as good as Sean O’Neil’s result.
So, for the best result I back to Sean O’Neil’s paper and Siggraph’93 paper “Display of The Earth Taking into Account Atmospheric Scattering” which Sean mentioned in CPU Gem2 to try to find a physical way to achieve accurate flexible atmosphere effect.
After researched these papers I realized it is impossible to get this flexible atmosphere without lookup table in vertex pass which SM2.0 cannot uses it. Because if you compare the Density Ratio Lookup tables which generated by different atmosphere height as below (Figure 1), you will see they are totally different curves which cannot use one equation to solved:
The algorithm of Lookup Table I used is based on Sean O’Neil’s one which he mentioned in GPU Gem2. This one is much better than Nishita 1993’s precalculated 2D lookup Table which only contains out-scattering for ray come from the sun.
In the 2D tables, the x dimension takes a sample point at a specific altitude above the planet, with 0.0 being on the ground and 1.0 being at the top of the atmosphere. The y dimension represents a vertical angle, with 0.0 being straight up and 1.0 being straight down. At each (x, y) pair in the table, a ray is fired from a point at altitude x to the top of the atmosphere along angle y. There are four lookup tables, two reserved for Rayleigh scattering (density and depth) and two reserved for Mie scattering (density and depth). You can put them in a float RGBA buffer. The Density’s range always from 0.0 to 1.0 (Figure 2), but not Depth. The Depth maximum value can over 90 which depends the atmosphere’s height, lower height bigger range. In Figure 3, you can see the Rayleigh Depth table and height map which 2.5% atmosphere’s height ratio.
Figure 2 Left: Rayleigh Density, Right: Mie Density
Figure 3 Left: Rayleigh Depth, Right: Depth height map
Implement it in Real-Time Shader
Since we need access lookup table as textures in vertex shader, we cannot use SM2.0 (you can try to use pixel shader in SM2.0 to achieve it but much more expensive), and the lookup tables have to be generated before rendering. That means you can not change atmosphere height in real-time (like some animation). But it is not bad thing, since usually the height of planet’s atmosphere will not change.
The shaders quite similar as Sean O’Neil’s samples, mainly difference is I replaced scale function with Lookup Table (GetDepth function). Here is the ground scattering vertex shader sample which implement in Unity3D:
In order to simply work pipeline, I created a tool which named AS3 to generate lookup table and setup them in planet’s surface and atmosphere shader in Unity3D. You can just easily setup planet’s parameter to you want (Atmosphere height ratio, Scale height … ), then just one click you will get your planet. For more details of the tool you can find in link:
Test and Demo
The result is as good as I want, I can defined any atmosphere height ratio to my sample planet. As below Figure 4, I can get extreme thick atmosphere which not exist in the world, so I also get interesting result since it has been calculated by physical way. Anyway this algorithm give me more flexibility to create planet and also physical based.
Figure 4 atmosphere height ratio = 100% (atmosphere radius is 2 times planet’s radius)
There is Demo to show you the result of different atmosphere height ratio planets. You can change the sun direction, camera FOV and fly in atmosphere to see sunset light scattering inside sky (you can tweak G value to see the difference of scattering direction when you fly in atmosphere).
AS3 Atmosphere Height Demo
(You will be asked to setup Unity Web Player to play this demo)