Atmospheric Scattering

Started by
6 comments, last by Shanee 13 years ago
I've been trying to implement atmospheric scattering shader for a while now. However the countless attempts i put into it has led me with insignificant process. So far I've been trying to implement the shader published by O'Neill into Render-Monkey using opengl/glsl. My current implementation has rendered the following images: http://img691.images....us/g/as01.png/ it's taking a lot more shape compared to my earlier attempts http://img253.images...attering01.png/

The problem I'm facing right now is that is that the sampled color is supposed to be 'v3FrontColor += v3Attenuate * fScaledLength * depth;' Currently I omit the scaling factor depth * fScaledLength. When I include these scalings everything will be pitch-black. The code of the my current implementations is http://ul.to/3f8jtkux:

uniform mat4 matView;
uniform vec4 view_position;
uniform vec3 v3LightPos;
uniform float fSize;

const int nSamples = 3;
const float fSamples = (float)(nSamples);
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*/ 6371;
const float fOuterRadius = /*fInnerRadius * 1.025*/ 6530.28f;
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 float fm_ESun = 15.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 v3CameraPos = vec3(0.0, fInnerRadius + (( fOuterRadius - fInnerRadius ) * fSize ), 0.0);
float fCameraHeight = length(v3CameraPos);
float fCameraHeight2 = fCameraHeight * fCameraHeight;

vec3 v3Pos = (gl_Vertex.xyz * fOuterRadius);
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 fStartAngle = dot(v3Start,v3Ray) / length(v3Start);
float fDepth = exp(fScaleOverScaleDepth * (-fInnerRadius + fCameraHeight));
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;
vec3 v3v3LightPosN = normalize(v3LightPos.xyz);

// Now loop through the sample rays
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0), v3Attenuate;
for(int i=0; i<1; i++)
{
float height = length (v3SamplePoint);
float depth = exp(fScaleOverScaleDepth * (fInnerRadius - height));
float lightAngle = dot(v3v3LightPosN, v3SamplePoint) / height;
float cameraAngle = dot(v3Ray, v3SamplePoint) / height;
float scatter = ( fStartOffset + depth * (scale (lightAngle) - scale (cameraAngle)));

v3Attenuate = exp(-scatter * (v3InvWavelength.xyz * fKr4PI + fKm4PI));
v3FrontColor += v3Attenuate /** fScaledLength * depth /** * */;
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;
c0 = vec4(v3FrontColor * (v3InvWavelength * fKrESun), 1.0); ;
c1 = vec4(v3FrontColor * fKmESun, 1.0);
v3Direction = v3CameraPos - v3Pos;

}


I would appreciate it if somebody could show me what I'm doing wrong, at this point everything starts to look like each-other.
Advertisement
From what I remember the example parameters given by O'Neill (at least in his GPU Gems article) are designed to work with a planet of radius 100 units, so if you are trying to apply the same example parameters to a planet with a massively different scale then they won't work correctly. Basically to really use this (like most things) you need to understand exactly what is going on in the shader. I eventually gave up trying to get this to just plug and play and instead worked out exactly what it was doing and after that I got it to work correctly.
My boyfriend uploaded a render monkey with Sean's atmospheric scattering here:
http://www.mirzaj.com/Downloads/HLSLDemo.rar

Hope it can help you in any way.

From what I remember the example parameters given by O'Neill (at least in his GPU Gems article) are designed to work with a planet of radius 100 units, so if you are trying to apply the same example parameters to a planet with a massively different scale then they won't work correctly.


It's true that I changed the parameters provided by O'Neil to parameters with substitutes that would semi-realistically map to the earths atmosphere. I used O'Neil variables at first, and it imposed the exact same problems. Nonetheless I've reverted my parameter substitutions, and right now I have a small console application mirroring the shader calculations for debugging. I don't really believe in using a shader blindly. So playing around with the variables until you get a lucky shot, I don't consider that to be a real alternative.


My boyfriend uploaded a render monkey with Sean's atmospheric scattering here:


Thanks Shanee, I'll try to analyze the shader. I have one small problem with the project as it is now, it seems to be broken. I can see the water/terrain/model, and there appears to be a day-night cycle judging from the dynamic change in colour but the actual sky-box doesn't seem to work. If i zoom out a bit, I do see a sphere with a star-texture somewhere in the scene but i think it was supposed to be around the camera. Are there any steps i should do to get it working? All resources seem to be substituted correctly, and all shaders seem to be built successfully.


//=====================================================
// RenderMonkey Error Log Created 4/8/2011 3:09 pm
//=====================================================
[RmApplicationImpl.cpp] (line 454): SUCCEEDED RMEffectInit()
[RmApplicationImpl.cpp] (line 461): SUCCEEDED AfxGetInstanceHandle()
[RmApplicationImpl.cpp] (line 467): SUCCEEDED LoadAccelerators()
[RmApplicationImpl.cpp] (line 473): SUCCEEDED AfxEnableControlContainer()


AMD RENDERMONKEY
DirectX Preview window: Selected 32-bit z-buffer bit depth using 24 bits for the depth channel and 8 bits for the stencil channel.
DirectX Preview Window: Enabled stencil buffer clearing with clear value of 0.
DirectX Preview window: Selected 32-bit RGB pixel format, where 8 bits are reserved for each color, as back buffer format.
DirectX Preview window: Selected 32-bit z-buffer bit depth using 24 bits for the depth channel and 8 bits for the stencil channel.
DirectX Preview Window: Enabled stencil buffer clearing with clear value of 0.
DirectX Preview window: Selected No multisamping selected.
DirectX Preview Window: Enabled depth buffer clearing with clear value of 1.000000.
DirectX Preview Window: Enabled stencil buffer clearing with clear value of 0.
DirectX Preview Window: Setting depth clear value to 1.000000
DirectX Preview Window: Setting stencil clear value to 0
DirectX Preview window: rendering on demand is disabled, will be rendering continuosly.
Compiling pixel shader API(D3D) /Scene/Scene/Atmospheric Scattering/Pixel Shader/ ...success
Compiling vertex shader API(D3D) /Scene/Scene/Atmospheric Scattering/Vertex Shader/ ...success
Compiling pixel shader API(D3D) /Scene/Scene/OceanDisplacement/Pixel Shader/ ...success
Compiling vertex shader API(D3D) /Scene/Scene/OceanDisplacement/Vertex Shader/ ...success
Creating Renderable Texture (IntermediateDisplacement) of dimensions (512, 512)... success.
Compiling pixel shader API(D3D) /Scene/Scene/Ocean/Pixel Shader/ ...success
Compiling vertex shader API(D3D) /Scene/Scene/Ocean/Vertex Shader/ ...success
Compiling pixel shader API(D3D) /Scene/Scene/SSAO Positions/Pixel Shader/ ...success
Compiling vertex shader API(D3D) /Scene/Scene/SSAO Positions/Vertex Shader/ ...success
Creating Renderable Texture (PositionBuffer) of dimensions (1294, 662)... success.
Compiling pixel shader API(D3D) /Scene/Scene/SSAO Normals/Pixel Shader/ ...success
Compiling vertex shader API(D3D) /Scene/Scene/SSAO Normals/Vertex Shader/ ...success
Creating Renderable Texture (NormalBuffer) of dimensions (1294, 662)... success.
Compiling pixel shader API(D3D) /Scene/Scene/SSAO/Pixel Shader/ ...success
Compiling vertex shader API(D3D) /Scene/Scene/SSAO/Vertex Shader/ ...success
Creating Renderable Texture (SSAOBuffer) of dimensions (512, 512)... success.
Compiling pixel shader API(D3D) /Scene/Scene/Scene/Pixel Shader/ ...success
Compiling vertex shader API(D3D) /Scene/Scene/Scene/Vertex Shader/
COMPILE WARNING: API(D3D) /Scene/Scene/Scene/Vertex Shader/ c:\program files\amd\rendermonkey 1.82\memory(96,4): warning X4000: Use of potentially uninitialized variable (Output)
In the code you posted, it appears you are only taking one sample. If you are, I believe that may affect the depth variable you commented out.

In the code you posted, it appears you are only taking one sample. If you are, I believe that may affect the depth variable you commented out.


Indeed I am only taking one sample. When i test my shader I test multiple permutations of it i.e. one with 1 sample, and one with multiple samples. So far non of that has lead to any positive results. I played around on my calculator for an day or so to investigation the range of those exp functions and it seems to be quite easily to get NaN/1#INF out of it. I believe this is also what happens with the color when i multiply it with scaling factors ( commented out).

In that case since attenuation is accumulative taking subsequent samples would increase the possibility of multiple samples to be NaN/Inf, since both cases any arithmetic operations with a valid number would result again in an invalid number. Feel free to correct me, if my theory is wrong. Good spot nonetheless
Yes, in the code we are using the sphere is supposed to follow the camera as our game doesn't support atmospheric exists at the moment. (it's also not a space game)

I thought it was set to be at your starting position or to follow the camera in the project, I can't quite remember though, will ask him when he wakes up.
Here you go, in render monkey settings, go to DirectX Settings and change the near view distance or near clip plane (or however it might be called there) to 0.1 instead of 1, then it will work.

If you ever implement this in DirectX, just get a bigger sphere. The problem is that the sphere's radius is just about 1 or 0.5.

This topic is closed to new replies.

Advertisement