Hello,

recently I have been trying to implement Sean O'Neil's atmospheric scattering shaders into a java project I have been working on (using jmonkey engine). I have the atmosphere from space shader working perfectly but for some reason I cannot get the ground from space shader working correctly. To see the planet at all I have to up the number of samples taken to ~400 and this is terribly inefficient and causes the color of the planet to be far too...orange. If anyone has any insight on this I would be extremely appreciative. I will include (what I think is relevant) relevant code/shaders. Thanks so much for the time!

The result I am getting using a diffuse color of (.85,.85,.85):

(what the color actually looks like sans shading: )

Starting here is how I render the spheres:

sun = new DirectionalLight(); sun.setColor(ColorRGBA.White); Vector3f LIGHT_DIRECTION = new Vector3f(0.5f, 0.5f, -0.5f).normalize(); sun.setDirection(LIGHT_DIRECTION); rootNode.addLight(sun); 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"); mat_A.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Front); setupSkyMaterial(mat_A); atm.setMaterial(mat_A); 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; }

the "Planet Class" simply contains all of the parameters (which I have checked many times to match them to O'Neil's). The setUpMaterial methods simply fetch these variables and pass them along to the shaders.

Here is the vertex shader (GroundFromSpace):

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_fOuterRadius2; // fOuterRadius^2 uniform float m_fInnerRadius; // The inner (planetary) radius uniform float m_fInnerRadius2; // fInnerRadius^2 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; uniform int m_nSamples; uniform float m_fSamples; varying vec4 c1; varying vec4 c0; 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) { // 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 - m_v3CameraPos; 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) / length(v3Pos); float fLightAngle = dot(m_v3LightPos, v3Pos) / length(v3Pos); float fCameraScale = scale(fCameraAngle); float fLightScale = scale(fLightAngle); float fCameraOffset = fDepth*fCameraScale; float fTemp = (fLightScale + fCameraScale); // Initialize the scattering loop variables float fSampleLength = fFar / m_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<m_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; } gl_FrontColor = vec4(v3FrontColor * (m_v3InvWavelength * m_fKrESun + m_fKmESun),1.0); gl_FrontSecondaryColor = vec4(v3Attenuate,1.0); gl_Position = g_WorldViewProjectionMatrix * inPosition; }

and here is the pixel shader (note that inColor is jmonkey's version of gl_Color and inPosition^^ is their version of gl_Vertex):

attribute vec4 inColor; varying vec4 c0, c1; void main (void) { gl_FragColor = inColor + 0.85 * gl_SecondaryColor; }

Again, thanks a lot for the time, any help whatsoever is appreciated.

**Edited by multifractal, 06 July 2013 - 06:39 AM.**