Atmospheric Scattering
Posted
by
Lawrence Kok
on Game Development
See other posts from Game Development
or by Lawrence Kok
Published on 2011-02-19T11:28:51Z
Indexed on
2011/02/19
15:33 UTC
Read the original article
Hit count: 542
I'm trying to implement atmospheric scattering based on Sean O`Neil algorithm that was published in GPU Gems 2. But I have some trouble getting the shader to work. My latest attempts resulted in: http://img253.imageshack.us/g/scattering01.png/
I've downloaded sample code of O`Neil from: http://http.download.nvidia.com/developer/GPU_Gems_2/CD/Index.html. Made minor adjustments to the shader 'SkyFromAtmosphere' that would allow it to run in AMD RenderMonkey.
In the images it is see-able a form of banding occurs, getting an blueish tone. However it is only applied to one half of the sphere, the other half is completely black. Also the banding appears to occur at Zenith instead of Horizon, and for a reason I managed to get pac-man shape.
I would appreciate it if somebody could show me what I'm doing wrong.
Vertex Shader:
uniform mat4 matView;
uniform vec4 view_position;
uniform vec3 v3LightPos;
const int nSamples = 3;
const float fSamples = 3.0;
const vec3 Wavelength = vec3(0.650,0.570,0.475);
const vec3 v3InvWavelength = 1.0f / vec3( Wavelength.x * Wavelength.x * Wavelength.x * Wavelength.x,
Wavelength.y * Wavelength.y * Wavelength.y * Wavelength.y,
Wavelength.z * Wavelength.z * Wavelength.z * Wavelength.z);
const float fInnerRadius = 10;
const float fOuterRadius = fInnerRadius * 1.025;
const float fInnerRadius2 = fInnerRadius * fInnerRadius;
const float fOuterRadius2 = fOuterRadius * fOuterRadius;
const float fScale = 1.0 / (fOuterRadius - fInnerRadius);
const float fScaleDepth = 0.25;
const float fScaleOverScaleDepth = fScale / fScaleDepth;
const vec3 v3CameraPos = vec3(0.0, fInnerRadius * 1.015, 0.0);
const float fCameraHeight = length(v3CameraPos);
const float fCameraHeight2 = fCameraHeight * fCameraHeight;
const float fm_ESun = 150.0;
const float fm_Kr = 0.0025;
const float fm_Km = 0.0010;
const float fKrESun = fm_Kr * fm_ESun;
const float fKmESun = fm_Km * fm_ESun;
const float fKr4PI = fm_Kr * 4 * 3.141592653;
const float fKm4PI = fm_Km * 4 * 3.141592653;
varying vec3 v3Direction;
varying vec4 c0, c1;
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 v3FrontColor = vec3(0.0, 0.0, 0.0);
vec3 v3Pos = normalize(gl_Vertex.xyz) * fOuterRadius;
vec3 v3Ray = v3CameraPos - v3Pos;
float fFar = length(v3Ray);
v3Ray = normalize(v3Ray);
// 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
for(int i=0; i<nSamples; i++)
{
float fHeight = length(v3SamplePoint);
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
float fLightAngle = dot(normalize(v3LightPos), v3SamplePoint) / fHeight;
float fCameraAngle = dot(normalize(v3Ray), v3SamplePoint) / fHeight;
float fScatter = (-fStartOffset + fDepth*( scale(fLightAngle) - scale(fCameraAngle)))/* 0.25f*/;
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
vec4 newPos = vec4( (gl_Vertex.xyz + view_position.xyz), 1.0);
gl_Position = gl_ModelViewProjectionMatrix * vec4(newPos.xyz, 1.0);
gl_Position.z = gl_Position.w * 0.99999;
c1 = vec4(v3FrontColor * fKmESun, 1.0);
c0 = vec4(v3FrontColor * (v3InvWavelength * fKrESun), 1.0);
v3Direction = v3CameraPos - v3Pos;
}
Fragment Shader:
uniform vec3 v3LightPos;
varying vec3 v3Direction;
varying vec4 c0;
varying vec4 c1;
const float g =-0.90f;
const float g2 = g * g;
const float Exposure =2;
void main(void){
float fCos = dot(normalize(v3LightPos), v3Direction) / length(v3Direction);
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 = c0 + fMiePhase * c1;
gl_FragColor.a = 1.0;
}
© Game Development or respective owner