Here is the vertex shader (GLSL):

uniform mat4 mvp; uniform mat4 mv; const vec3 v3CameraPos = vec3(0.0, 0.0, 6.378); // The camera's current position const vec3 v3LightPos = normalize(vec3(0.0, 0.0, 1.0)); // The direction vector to the light source const vec3 v3InvWavelength = vec3(1.0 / pow(0.650, 4.0), 1.0 / pow(0.570, 4.0), 1.0 / pow(0.475, 4.0)); // 1 / pow(wavelength, 4) for the red, green, and blue channels const float fCameraHeight = 6.378; // The camera's current height const float fCameraHeight2 = 6.378 * 6.378; // fCameraHeight^2 const float fOuterRadius = 6.53745; // The outer (atmosphere) radius const float fOuterRadius2 = 6.53745 * 6.53745; // fOuterRadius^2 const float fInnerRadius = 6.378; // The inner (planetary) radius const float fInnerRadius2 = 6.378 * 6.378; // fInnerRadius^2 const float fKrESun = 0.0025 * 15.0; // Kr * ESun const float fKmESun = 0.0015 * 15.0; // Km * ESun const float fKr4PI = 0.0025 * 4.0 * 3.1415; // Kr * 4 * PI const float fKm4PI = 0.0015 * 4.0 * 3.1415; // Km * 4 * PI const float fScale = 1.0 / (6.53745 - 6.378); // 1 / (fOuterRadius - fInnerRadius) const float fScaleDepth = 0.25; // The scale depth (i.e. the altitude at which the atmosphere's average density is found) const float fScaleOverScaleDepth = (1.0 / (6.53745 - 6.378)) / 0.25; // fScale / fScaleDepth const int nSamples = 2; const float fSamples = 2.0; varying vec3 v3Direction; float scale(float fCos) { float x = 1.0 - fCos; return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); } void main(void) { // Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere) vec3 v3Pos = gl_Vertex.xyz; vec3 v3Ray = v3Pos - v3CameraPos; float fFar = length(v3Ray); v3Ray /= fFar; // Calculate the ray's starting position, then calculate its scattering offset vec3 v3Start = v3CameraPos; float fHeight = length(v3Start); float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fCameraHeight)); float fStartAngle = dot(v3Ray, v3Start) / fHeight; float fStartOffset = fDepth*scale(fStartAngle); // Initialize the scattering loop variables float fSampleLength = fFar / fSamples; float fScaledLength = fSampleLength * fScale; vec3 v3SampleRay = v3Ray * fSampleLength; vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; // Now loop through the sample rays vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); for(int i=0; i<nSamples; i++) { float fHeight = length(v3SamplePoint); float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight)); float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight; float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight; float fScatter = (fStartOffset + fDepth*(scale(fLightAngle) - scale(fCameraAngle))); vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI)); v3FrontColor += v3Attenuate * (fDepth * fScaledLength); v3SamplePoint += v3SampleRay; } // Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader gl_FrontSecondaryColor.rgb = v3FrontColor * fKmESun; gl_FrontColor.rgb = v3FrontColor * (v3InvWavelength * fKrESun); gl_Position = mvp * gl_Vertex; v3Direction = v3CameraPos - v3Pos; }

and the fragment shader:

const vec3 v3LightPos = normalize(vec3(0.0, 0.0, 1.0)); const float g = -0.95; const float g2 = -0.95 * -0.95; varying vec3 v3Direction; void main (void) { float fCos = dot(v3LightPos, v3Direction) / length(v3Direction); float fRayleighPhase = 0.75 * (1.0 + fCos*fCos); float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5); gl_FragColor = fRayleighPhase * gl_Color + fMiePhase * gl_SecondaryColor; }

This is the output I get (when looking up). Just a hit of blue at the top of the sky dome and a grey-white color everywhere else:

Can anyone see where I am going wrong?