Atmosphere Shader         Atmosphere shader as viewed from space

Description

This shader is used to create atmospheric rings around a planet as depicted in the picture below:
Image

Usage

You will need to assign this material to a sphere that is a little bigger then your planet. Also you will need to give this shader the radius of your planet and the radius of the sphere you use as the atmosphere. You can do that with this line of code

//Create our entity
AtmosphereEntity = sm->createEntity(PlanetName + "_atm_Ent",PlanetName + "_atm");
//assign it our material
AtmosphereEntity->setMaterialName ("Atmosphere");
//also this will make the atmosphere to be rendered behind the planet
AtmosphereEntity->setRenderQueueGroup (Ogre::RENDER_QUEUE_BACKGROUND);
//here you will replace PlanetRadius and AtmosphereRadius with your values
AtmosphereEntity->getSubEntity (0)->setCustomParameter (0, Ogre::Vector4(PlanetRadius,AtmosphereRadius,0,0));


And here is the gradient you need as a texture (just right click / save image as and save it into your media folder)
Image

WARNING : It is extremely important that you do not rotate the atmosphere holding sphere, as this will screw up the shader!!!

Atmosphere.material

vertex_program AtmosphereVertexProgram hlsl
{
    source Atmosphere.hlsl
    entry_point main2VS
    target vs_2_0
	
	default_params                    
    {
        param_named_auto lightPos light_position_object_space 0
        param_named_auto WorldXf world_matrix
	param_named_auto ViewIXf camera_position_object_space
	param_named_auto WorldViewProj worldviewproj_matrix
    }
}

fragment_program AtmosphereFragmentProgram hlsl
{
	source Atmosphere.hlsl
	entry_point mainBPS
	target ps_2_0
}

material Atmosphere
{
	technique
	{

		pass
		{
			depth_check off
			depth_write off
			scene_blend one one_minus_src_alpha 

			vertex_program_ref AtmosphereVertexProgram
			{
				param_named_auto SurfaceAtmosphereRadius4 custom 0
			}

			fragment_program_ref AtmosphereFragmentProgram
			{
			}

			texture_unit
			{
				texture AtmosphereGradient.jpg
				tex_address_mode clamp clamp
				filtering linear linear linear
			}
		}
	}
}

Atmosphere.hlsl

void main2VS(
    float3 pos : POSITION,
    uniform float4 lightPos,
	uniform float4x4 WorldXf,
	uniform float4 ViewIXf,
	uniform float4x4 WorldViewProj,
	uniform float4 SurfaceAtmosphereRadius4,
 
    out float4 oPosition: POSITION,
    out float2 oUV: TEXCOORD0,
    out float oAlpha: TEXCOORD1,
    out float3 oCamToPos: TEXCOORD2,
    out float3 oLightDir :TEXCOORD3
    ) 
{
	float SurfaceRadius = SurfaceAtmosphereRadius4.x;
	float AtmosphereRadius = SurfaceAtmosphereRadius4.y;
	float StretchAmt = 0.5f;

    float4 Po = float4(pos.xyz,1);
    float4 Pw = mul(WorldXf, pos);
    float3 position = Pw.xyz;
    float4 camPos = ViewIXf;
 
    oPosition = mul(WorldViewProj, Po); 
 
    float radius = length(position);
    float radius2 = radius * radius; 
    float camHeight = length(camPos.xyz);
    float3 camToPos = position - camPos.xyz;
    float farDist = length(camToPos);
 
    float3 lightDir = normalize(lightPos.xyz);
    float3 normal = normalize(position);
 
    float3 rayDir = camToPos / farDist;
    float camHeight2 = camHeight * camHeight;
 
    // Calculate the closest intersection of the ray with the outer atmosphere
    float B = 2.0 * dot(camPos.xyz, rayDir);
    float C = camHeight2 - radius2;
    float det = max(0.0, B*B - 4.0 * C);
    float nearDist = 0.5 * (-B - sqrt(det));
    float3 nearPos = camPos.xyz + (rayDir * nearDist);
    float3 nearNormal = normalize(nearPos);

    // get dot products we need
    float lc = dot(lightDir, camPos / camHeight);
    float ln = dot(lightDir, normal);
    float lnn = dot(lightDir, nearNormal);

    // get distance to surface horizon
    float altitude = camHeight - SurfaceRadius;
    float horizonDist = sqrt((altitude*altitude) + (2.0 * SurfaceRadius * altitude));
    float maxDot = horizonDist / camHeight;
 
    // get distance to atmosphere horizon - use max(0,...) because we can go into the atmosphere
    altitude = max(0,camHeight - AtmosphereRadius);
    horizonDist = sqrt((altitude*altitude) + (2.0 * AtmosphereRadius * altitude));
 
    // without this, the shift between inside and outside atmosphere is  jarring
    float tweakAmount = 0.1;
    float minDot = max(tweakAmount,horizonDist / camHeight);
 
    // scale minDot from 0 to -1 as we enter the atmosphere
    float minDot2 = ((camHeight - SurfaceRadius) * (1.0 / (AtmosphereRadius  - SurfaceRadius))) - (1.0 - tweakAmount);
    minDot = min(minDot, minDot2);
  
    // get dot product of the vertex we're looking out
    float posDot = dot(camToPos / farDist,-camPos.xyz / camHeight) - minDot;
 
    // calculate the height from surface in range 0..1
    float height = posDot * (1.0 / (maxDot - minDot));
 
    // push the horizon back based on artistic taste
    ln = max(0,ln + StretchAmt);
    lnn = max(0,lnn + StretchAmt);

    // the front color is the sum of the near and far normals
    float brightness = saturate(ln + (lnn * lc));
 
    // use "saturate(lc + 1.0 + StretchAmt)" to make more of the sunset side color be used when behind the planet
    oUV.x = brightness * saturate(lc + 1.0 + StretchAmt);
    oUV.y = height;
 
    // as the camera gets lower in the atmosphere artificially increase the height
    // so that the alpha value gets raised and multiply the increase amount
    // by the dot product of the light and the vertex normal so that 
    // vertices closer to the sun are less transparent than vertices far from the sun.
    height -= min(0.0,minDot2 + (ln * minDot2));
    oAlpha = height * brightness;
 
    // normalised camera to position ray
    oCamToPos = -rayDir;
 
    oLightDir = normalize(lightPos.xyz - position.xyz); 
}

float4 mainBPS( 
    float2 uv : TEXCOORD0,
    float alpha : TEXCOORD1,
    float3 camToPos : TEXCOORD2,
    float3 lightDir :TEXCOORD3,
    uniform sampler2D TexSampler
) : COLOR {
 
	float Atmosphere_G = -0.95f;
	
    const float fExposure = 1.5;
    float g = Atmosphere_G;
    float g2 = g * g;

    // atmosphere color
    float4 diffuse = tex2D(TexSampler,uv);
 
    // sun outer color - might could use atmosphere color
    float4 diffuse2 = tex2D(TexSampler,float2(min(0.5,uv.x),1));

    // this is equivilant but faster than fCos = dot(normalize(lightDir.xyz),normalize(camToPos));
    float fCos = dot(lightDir.xyz,camToPos) * rsqrt( dot(lightDir.xyz,lightDir.xyz) * dot(camToPos,camToPos));
    float fCos2 = fCos * fCos;

    // apply alpha to atmosphere
    float4 diffuseColor = diffuse * alpha;
    
    // sun glow color
    float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos2) /(1.0 + g2 - 2.0*g*fCos);
    float4 mieColor = diffuse2 * fMiePhase * alpha;
  
    // use exponential falloff because mie color is in high dynamic range
    // boost diffuse color near horizon because it gets desaturated by falloff
    return 1.0 - exp((diffuseColor * (1.0 + uv.y) + mieColor) * -fExposure);
}

Credits

Full credits go to Alex Peterson over at his blog. I only converted the .fx he posted over there to ogre material.