Jump to content

  • Log In with Google      Sign In   
  • Create Account


Atmospheric Scattering


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
4 replies to this topic

#1 _Unicron_   Members   -  Reputation: 253

Like
0Likes
Like

Posted 30 June 2011 - 06:30 PM

I'm trying to implement atmospheric scattering using O'Neill's algorithm from GPU gems 2. I only need to render the atmosphere from the ground. To do this I create a half sphere of radius 6.53745. In the shaders I have hard-coded all of the parameters while I try and get something working. Due to the player remaining at ground level I have also hard-coded the camera position within the vertex shader to be at the planet radius.

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:

Posted Image


Can anyone see where I am going wrong?

Sponsor:

#2 _Unicron_   Members   -  Reputation: 253

Like
0Likes
Like

Posted 01 July 2011 - 10:21 AM

Update: I'm not sure if I'm looking in the right place but small changes to the size of skydome result in drastic changes to the output (nothing that looks anything like correct through). Although I thought this was set correctly. Unless I'm missing something subtle?

#3 bluntman   Members   -  Reputation: 234

Like
0Likes
Like

Posted 01 July 2011 - 10:33 AM

Try moving the camera height up a bit from the inner radius, like + 0.1 maybe.

#4 _Unicron_   Members   -  Reputation: 253

Like
0Likes
Like

Posted 01 July 2011 - 10:40 AM

Try moving the camera height up a bit from the inner radius, like + 0.1 maybe.


Hi Bluntman, I have tried as you have suggested and the result is basically the same, the only difference is the little patch of blue that you can see in the image I posted is a little darker.

P.S The planet rendering link in your sig is very nice, I'm jealous :)


#5 _Unicron_   Members   -  Reputation: 253

Like
0Likes
Like

Posted 01 July 2011 - 11:14 AM

I have fixed the problem :)

It turns out it was actually working. I wasn't positioning the camera correctly in the sky dome. I moved the dome down and things looked a lot better. The sky color looks a little dark at the moment but I'm sure that's fixable :)

Posted Image


Posted Image




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS