Sign in to follow this  

Atmospheric Scattering

Recommended Posts

Thergothon    160
I'm trying to implement atmospheric scattering from the Nielsons paper: "Real Time Rendering of Atmospheric Scattering Effects for Flight Simulators", and there is a couple of things I don't understand. In appendix e.2, he uses a rayleigh and mie multiplier and applies that to both the rayleigh and mie coefficients. I'm assuming that it is some xyz to rgb conversion multiplier as the xyz values for the rayleigh and mie constants are extremely small and would explain why my sky is black, but I can't find anywhere in the paper that describes where he gets these constants from. Also, I can't find where he gets the density values that are uploaded into the shader in appendix e.2, which are then used to calculate the particle and molecular optical depth used in the extinction calculation. I'm assuming that they are from equations 5.9 and 5.10, but where does the value c come from? Is that the constant used to calculate the mie coefficient?

Share this post

Link to post
Share on other sites
Sark7    122
Did you check the Preetham's "A Practical Analytic Model for Daylight"?
It may contain some of formulas you need.

Share this post

Link to post
Share on other sites
Thergothon    160
That paper didn't help me much, it seems to use a different approach using constant tables to provide a pretty good approximation. I also checked out the ATI paper and all their formulas match the ones in the paper I mentioned above. I decided to drop the altitude density stuff from the simulation to simplify it, so I could at least get it looking good from ground level first. I'll post source snippets, and maybe somebody can point out where I am going wrong.

Coefficient calculations:

float r = 1.0f/650e-9f; //red - 650nm
float g = 1.0f/610e-9f; //green - 610nm
float b = 1.0f/475e-9f; //blue - 475nm

float r2 = r*r;
float g2 = g*g;
float b2 = b*b;

float r4 = r2*r2;
float g4 = g2*g2;
float b4 = b2*b2;

//calculate rayleigh scattering coefficient
//br = (8pi^3(n^2 - 1)^2)/(3Nw^4)
//n = refractive index of air
//N = molecular density
//w = wavelength of light
float n = 1.0002926f;
float N = 2.545e25f;
float temp = 8.0f*D3DX_PI*D3DX_PI*D3DX_PI/(3.0f*N);
float temp2 = (n*n - 1.0f)*(n*n - 1.0f);

m_rayleigh.x = temp*temp2*r4;
m_rayleigh.y = temp*temp2*g4;
m_rayleigh.z = temp*temp2*b4;

//calculate mie scattering coefficient
//bm = 0.424*c*pi*(4pi^2/w^2)*K
//c = (0.6544*T - 0.6510)*10^-16
// T = turbidity
//w = wavelength of light
//K ~ 0.67 (varies with colour)
float T = 555e-9f;
float c = (0.6544f*T - 0.6510f)*1e-16f;

temp = 0.67f*0.424f*c*D3DX_PI;

m_mie.x = temp*(4.0f*D3DX_PI*D3DX_PI*r2);
m_mie.y = temp*(4.0f*D3DX_PI*D3DX_PI*g2);
m_mie.z = temp*(4.0f*D3DX_PI*D3DX_PI*b2);

//store henyey greenstein constants
//HG = (1 - g^2)/(4pi(1 + g^2 - 2g*cos(theta)^3/2)
//g = directionality constant
g = 0.55f;
m_hg.x = 1.0f - g*g;
m_hg.y = 1.0f + g*g;
m_hg.z = 2.0f*g;
m_hg.w = 4.0f*D3DX_PI;

//store scaled scattering coefficients for phase functions
m_rayleigh2 = m_rayleigh * 3.0f/(16.0f*D3DX_PI);
m_mie2 = m_mie/(4.0f*D3DX_PI);

//store constant in inscattering function
m_inscatter.x = 1.0f/(m_rayleigh.x + m_mie.x);
m_inscatter.y = 1.0f/(m_rayleigh.y + m_mie.y);
m_inscatter.z = 1.0f/(m_rayleigh.z + m_mie.z);

Sky shader:

float4x4 world;
float4x4 viewProj;

float4 sun; //sunlight colour + intensity
float3 lightDir; //sunlight direction

float3 rayleigh; //rayleigh coefficient
float3 rayleigh2; //rayleigh * phase coefficient
float3 mie; //mie coefficient
float3 mie2; //mie * phase coefficient
float4 hg; //henyey greenstein phase function constants
float3 inscatter; //inscattering coefficient

struct vsin{
float3 pos : POSITION;
float3 norm: NORMAL;
float2 tex : TEXCOORD0; //optical depth in y

struct vsout {
float4 final : POSITION;
float4 colour : COLOR0;

void VS(in vsin input, out vsout output) {

//transform to world space = mul(float4(input.pos, 1.0), world);

//transform to homogenous view space = mul(, viewProj);

//transform norm to world space
input.norm = mul(input.norm, (float3x3) world);

//calculate angle between view vector and sun direction
//viewer at centre of dome, so view vector = norm
float2 viewAngle;
viewAngle.x = dot(-lightDir, input.norm);

//calculate scaled viewing angle for rayleigh scattering function
//3/16pi * rayleigh * (2 + 0.5*cos2(theta))
viewAngle.y = 2.0 + 0.5*(viewAngle.x * viewAngle.x);

//calculate extinction terms
//1.0f - e^(-(rayleigh + mie) * ray length)
float3 extinction = 1.0 - exp((-rayleigh + mie)*input.tex.y);

//calculate henyey greenstein mie scattering approximation
//m = (1 - g^2)/(4pi(1 + g^2 + 2gcos(theta))^(3/2))
//hg = {1 - g^2, 1 + g^2, 2g, 4pi};
float temp = hg.x/(hg.w*pow(hg.y + hg.z*viewAngle.x, 1.5));

//calculate inscattering
//(r(theta) + m(theta))/(r + m)*sun*extinction;
float3 r = rayleigh2 * viewAngle.y;
float3 m = mie2 * temp;

float3 i = (r + m)*inscatter**extinction;
i *= sun.w; //multiply by sun intensity

//output the final colour
float4 colour = {i.x, i.y, i.z, 1.0};
output.colour = colour;


struct psin {
float4 colour : COLOR0;

float4 PS(in psin input) : COLOR {
return input.colour;

technique sky {
pass P0 {
VertexShader = compile vs_2_0 VS();
PixelShader = compile ps_1_1 PS();

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this