# GLSL Atmospheric Scattering Issue

I am attempting to use Sean O'Neil's shaders to accomplish atmospheric scattering. For now I am just using SkyFromSpace and GroundFromSpace. The atmosphere works fine but the planet itself is just a giant dark sphere with a white blotch that follows the camera. I think the problem might rest in the "v3Attenuation" variable as when this is removed the sphere is show (albeit without scattering). Here is the vertex shader. Thanks for the time!

uniform mat4 g_WorldViewProjectionMatrix;
uniform mat4 g_WorldMatrix;
uniform vec3 m_v3CameraPos;     // The camera's current position
uniform vec3 m_v3LightPos;      // The direction vector to the light source
uniform vec3 m_v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
uniform float m_fCameraHeight;  // The camera's current height
uniform float m_fCameraHeight2; // fCameraHeight^2
uniform float m_fOuterRadius;       // The outer (atmosphere) radius
uniform float m_fInnerRadius;       // The inner (planetary) radius
uniform float m_fKrESun;            // Kr * ESun
uniform float m_fKmESun;            // Km * ESun
uniform float m_fKr4PI;         // Kr * 4 * PI
uniform float m_fKm4PI;         // Km * 4 * PI
uniform float m_fScale;         // 1 / (fOuterRadius - fInnerRadius)
uniform float m_fScaleDepth;        // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
uniform float m_fScaleOverScaleDepth;   // fScale / fScaleDepth

attribute vec4 inPosition;

vec3 v3ELightPos = vec3(g_WorldMatrix * vec4(m_v3LightPos, 1.0));
vec3 v3ECameraPos= vec3(g_WorldMatrix * vec4(m_v3CameraPos, 1.0));

const int nSamples = 2;
const float fSamples = 2.0;

varying vec4 color;

float scale(float fCos)
{
float x = 1.0 - fCos;
return m_fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
}

void main(void)
{

gl_Position = g_WorldViewProjectionMatrix * inPosition;
// 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 = vec3(g_WorldMatrix * inPosition);
vec3 v3Ray = v3Pos - v3ECameraPos;
float fFar = length(v3Ray);
v3Ray /= fFar;

// Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere)
float B = 2.0 * dot(m_v3CameraPos, v3Ray);
float C = m_fCameraHeight2 - m_fOuterRadius2;
float fDet = max(0.0, B*B - 4.0 * C);
float fNear = 0.5 * (-B - sqrt(fDet));

// Calculate the ray's starting position, then calculate its scattering offset
vec3 v3Start = m_v3CameraPos + v3Ray * fNear;
fFar -= fNear;
float fDepth = exp((m_fInnerRadius - m_fOuterRadius) / m_fScaleDepth);
float fCameraAngle = dot(-v3Ray, v3Pos) / fFar;
float fLightAngle = dot(v3ELightPos, v3Pos) / fFar;
float fCameraScale = scale(fCameraAngle);
float fLightScale = scale(fLightAngle);
float fCameraOffset = fDepth*fCameraScale;
float fTemp = (fLightScale + fCameraScale);

// Initialize the scattering loop variables
float fSampleLength = fFar / fSamples;
float fScaledLength = fSampleLength * m_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);
vec3 v3Attenuate;
for(int i=0; i<nSamples; i++)
{
float fHeight = length(v3SamplePoint);
float fDepth = exp(m_fScaleOverScaleDepth * (m_fInnerRadius - fHeight));
float fScatter = fDepth*fTemp - fCameraOffset;
v3Attenuate = exp(-fScatter * (m_v3InvWavelength * m_fKr4PI + m_fKm4PI));
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
v3SamplePoint += v3SampleRay;
}
vec3 first = v3FrontColor * (m_v3InvWavelength * m_fKrESun + m_fKmESun);
vec3 secondary = v3Attenuate;
color = vec4((first +  vec3(0.25,0.25,0.25) * secondary), 1.0);
// ^^ that color is passed to the frag shader and is used as the gl_FragColor

}


Here is also an image of the problem:

Something strange of note: there is a different effect present when I use gl_Color and a varying variable. This is what I get when I use gl_FragColor = vec4( c0 + vec3(0.25,0.25,0.30), 1.0); where c0 is the varying version of "first" below:

and here is the product when gl_Color.rgb is used in place of c0 and c0 is replaced with gl_FrontColor on the vertex side:

And finally when gl_Color and gl_Secondary color are used together the sphere is entirely black with a white blotch as seen above...

EDIT: Here is the section where I create the spheres and apply their corresponding materials:

    Mesh plan = makePlanet();
pla = new Geometry("Mesh" , plan);
mat_P = new Material(assetManager, "GroundFromSpace.j3md");
setupGroundMaterial(mat_P);
pla.setMaterial(mat_P);
Mesh atmosphere = makeAtmosphere();
atm = new Geometry("Mesh", atmosphere);
mat_A = new Material(assetManager, "SkyFromSpace.j3md");
setupSkyMaterial(mat_A);
atm.setMaterial(mat_A);


setUpMaterial(); just enters the scattering parameters into the shaders.

public Mesh makePlanet(){
planet = new Planet(4, new Vector3f(0,0,0));
Mesh pl = new Sphere(128,128,planet.getRadius());
return pl;


}

public Mesh makeAtmosphere(){
Mesh atmosphere = new Sphere(128, 128, planet.getOuterRadius());
return atmosphere;


}

Something interesting. I changed the number of samples taken in ground from space scattering from 4 to 400 and the following result was observed: The color still isn't right (it's supposed to be (0.25,0.25,0.25)) and this obviously isn't a fix since the number of samples should be much less...But why could this be happening?

• See if this helps: gamedev.stackexchange.com/questions/50373/… – msell Jun 30 '13 at 5:11
• Hmm while that is interesting I did try what that person did in generating and setting the color (sort of what I did above) and the same effect is present. – mtf1200 Jun 30 '13 at 8:23

It is not entirely clear how you are applying your shaders or how you are rendering the spheres.

In O'Neil's examples the planet consists of two spheres with radiuses m_fInnerRadius (ground) and m_fOuterRadius (atmosphere). The spheres are rendered individually where GroundFromSpaceShader is blended with the terrain texture to form surface and the back-facing triangles of the outer sphere are rendered to act as atmosphere.

I've found that common mistakes with Sean O'Neil's shaders are related to distance between camera to the center of the sphere and forgetting that the original SkyFromSpace shader is expected to be rendered only on triangles that are backwards facing.

First problem is easy to solve. You need to ensure that your camera is outside of the sphere's radius. This means that length of the vector from the camera position to the center of the sphere must be bigger than m_fOuterRadius. Bear in mind, that this is only the case with these two specific shaders.

The second problem is just as easy: you need to change the winding order of your triangles or use clock-wise with glFrontFace (or similar API call) instead of counter clock-wise.

The shaders are based on a model that is not exactly trivial to implement and relies on a function that O'Neil found using curve approximation software. The consensus online seems to be that the function is extremely picky in terms of parameters, which can also be part of your problem.

Best advice I can give to you is to take O'Neil's working sandbox and see the sources for yourself. In your own code, it is good idea to make each parameter adjustable real-time so that you can see how the parameters affect. Some parameters seem to have very little effect, while others are few tenths away from showing nothing instead of everything.

• Well the spheres are created simply: Sphere sphere = new Sphere(..); (this is java). And there are two, my inner, planet, sphere has a radius of 10 and my atmosphere has one of 10.25. The camera is outside of the atmosphere as seen in the shots above. And good point about the parameters I will try mirroring O'Neils'. – mtf1200 Jul 1 '13 at 8:44
• Could you post the code to the GL calls where you actually render. If you are using jMonkeyEngine you might want to check out this: code.google.com/p/jme3-atmosphere-scattering – ollipekka Jul 1 '13 at 9:27
• I am using jMonkey. The code you linked as been a great source of reference to me. I will edit the post to include the section where I create the sphere and attach the materials (the programs) to them. – mtf1200 Jul 2 '13 at 6:44

I was being careless and simply wasn't passing the square of the outter radius correctly. Fixing this fixed all issues. Thanks for the input!