Skip to main content
GameDev.net gamedev.net
🔒 Locked

[SOLVED] Trying to use Atmospheric Scattering (O'Neill 2004) but get black sphere.

Started by DanoruX Jan 2, 2011 at 11:27 PM 2 replies 5.5k views
Original Post
DanoruX
DanoruX
Hi guys and girls, I'm trying to use Atmospheric Scattering (O'Neill 2004) but only get black sphere. The shaders being used are 99% copy/pasted from GPU gems 2, but with comments removed (comments won't compile for some reason).

I've tried changing gl_FrontColor to see if the faces are in the wrong direction, but I can set a color and see it pass through the fragment shader just fine. However, using the actual scattering algorithm is a no go right now and I can't figure out what's causing it to zero out. Am I missing something?

For reference, here they are:

Vertex Shader:
uniform vec3 v3CameraPos;uniform vec3 v3LightPos;		uniform vec3 v3InvWavelength;	uniform float fCameraHeight;	uniform float fCameraHeight2;	uniform float fOuterRadius;		uniform float fOuterRadius2;	uniform float fInnerRadius;		uniform float fInnerRadius2;	uniform float fKrESun;			uniform float fKmESun;			uniform float fKr4PI;			uniform float fKm4PI;		uniform float fScale;			uniform float fScaleDepth;		uniform float fScaleOverScaleDepth;const int nSamples = 4;const float fSamples = 4.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){	vec3 v3Pos = gl_Vertex.xyz;	vec3 v3Ray = v3Pos - v3CameraPos;	float fFar = length(v3Ray);	v3Ray /= fFar;	vec3 v3Start = v3CameraPos;	float fHeight = length(v3Start);	float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fCameraHeight));	float fStartAngle = dot(v3Ray, v3Start) / fHeight;	float fStartOffset = fDepth*scale(fStartAngle);	float fSampleLength = fFar / fSamples;	float fScaledLength = fSampleLength * fScale;	vec3 v3SampleRay = v3Ray * fSampleLength;	vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;	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;	}	gl_FrontSecondaryColor.rgb = v3FrontColor * fKmESun;	gl_FrontColor.rgb = v3FrontColor * (v3InvWavelength * fKrESun);		gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;	v3Direction = v3CameraPos - v3Pos;}


Fragment Shader:
uniform vec3 v3LightPos;uniform float g;uniform float g2;varying vec3 v3Direction;void main (void){	float fCos = dot(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 = gl_Color + fMiePhase * gl_SecondaryColor;	gl_FragColor.a = gl_FragColor.b;}


And here is how I feed the parameters into the shader:

glUseProgram(sky_shader);	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);		GLint v3CameraPos, v3LightPos, v3InvWavelength, 		fCameraHeight, fCameraHeight2, 		fInnerRadius, fInnerRadius2, fOuterRadius, fOuterRadius2, 		fKrESun, fKmESun, fKr4PI, fKm4PI, fScale, fScaleDepth, fScaleOverScaleDepth,		g, g2;		glGetUniformLocation(v3CameraPos, "v3CameraPos");	glUniform3f(v3CameraPos, 0, 1, 0);	glGetUniformLocation(v3LightPos, "v3LightPos");	glUniform3f(v3LightPos, sun_x / sqrt(sun_x * sun_x + sun_y * sun_y), sun_y / sqrt(sun_x * sun_x + sun_y * sun_y), 0);	glGetUniformLocation(v3InvWavelength, "v3InvWavelength");	glUniform3f(v3InvWavelength, 1.0 / pow(0.650, 4.0), 1.0 / pow(0.570, 4.0), 1.0 / pow(0.475, 4.0));	glGetUniformLocation(fCameraHeight, "fCameraHeight");	glUniform1fARB(fCameraHeight, 1);	glGetUniformLocation(fCameraHeight2, "fCameraHeight2");	glUniform1fARB(fCameraHeight2, 1);	glGetUniformLocation(fInnerRadius, "fInnerRadius");	glUniform1fARB(fInnerRadius, 6356.7523142);	glGetUniformLocation(fInnerRadius2, "fInnerRadius2");	glUniform1fARB(fInnerRadius2, 6356.7523142 * 6356.7523142);	glGetUniformLocation(fOuterRadius, "fOuterRadius");	glUniform1fARB(fOuterRadius, 6452.103598913);	glGetUniformLocation(fOuterRadius2, "fOuterRadius2");	glUniform1fARB(fOuterRadius2, 6452.103598913 * 6452.103598913);	glGetUniformLocation(fKrESun, "fKrESun");	glUniform1fARB(fKrESun, 0.0025 * 20.0);	glGetUniformLocation(fKmESun, "fKmESun");	glUniform1fARB(fKmESun, 0.0015 * 20.0);	glGetUniformLocation(fKr4PI, "fKr4PI");	glUniform1fARB(fKr4PI, 0.0025 * 4.0 * 3.141592653);	glGetUniformLocation(fKm4PI, "fKm4PI");	glUniform1fARB(fKm4PI, 0.0015 * 4.0 * 3.141592653);	glGetUniformLocation(fScale, "fScale");	glUniform1fARB(fScale, 1.0 / (6452.103598913 - 6356.7523142));	glGetUniformLocation(fScaleDepth, "fScaleDepth");	glUniform1fARB(fScaleDepth, 0.25);	glGetUniformLocation(fScaleOverScaleDepth, "fScaleOverScaleDepth");	glUniform1fARB(fScaleOverScaleDepth, 4.0 / (6452.103598913 - 6356.7523142));	glGetUniformLocation(g, "g");	glUniform1fARB(g, -0.85);	glGetUniformLocation(g2, "g2");	glUniform1f(g2, -0.85 * -0.85);


Rendering:
glRotated(CAMERA->rotation->x, 1, 0, 0);	glRotated(CAMERA->rotation->y, 0, 1, 0);	glTranslated(0,-EARTH_RADIUS -CAMERA->position->y / 1000,0);	gluSphere(sky_sphere, EARTH_ATMOSPHERE_RADIUS, 128, 128);


[Edited by - DanoruX on January 3, 2011 2:08:02 PM]
karwosts
karwosts
Don't have a particular answer for whats wrong with your situation, but I implemented something similar a while back and these things are really difficult to get right, it will very easily saturate to 0 or 1 unless you get the variables just right. There's a lot of tweaking and random fudge-factor constants you need to get a good looking result.

That in mind, maybe you would consider implementing the entire algorithm on your CPU until you get a good feel for the equations? GLSL is tough for this being so limited in it's debugging tools. It's a lot easier to port into your GPU when you already know the equations/constants you need.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
DanoruX
DanoruX
Uh oh.... I just realized I'm doing something really stupid - none of the uniforms are getting passed in. But fixing it is proving difficult as the usual culprit of not setting the program first is invalid - setting the right shader is the first thing I'm doing and yet....

EDIT: I shouldn't have written code after 11pm, I've mostly solved all my problems. Will post screenshot when done.

EDIT2: I've narrowed my problem(s?) down to fScatter becoming really huge and, as a consequence, the attenuation becomes really, really small.

[Edited by - DanoruX on January 3, 2011 11:39:17 AM]
DanoruX
DanoruX


Got it working, Turns out I forgot to add innerradius to my camera position/height. HDR is easy after this. [grin]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.