Jump to content
  • Advertisement
Sign in to follow this  

Atmospheric Scattering

This topic is 4417 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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
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
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
output.final = mul(float4(input.pos, 1.0), world);

//transform to homogenous view space
output.final = mul(output.final, 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*sun.xyz*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
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!