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

Why is my sky so dark? (single scattering atmosphere question)

Started by CoderFish Jul 1, 2009 at 5:55 PM 2 replies 2.1k views
Original Post
CoderFish
CoderFish
Hi everybody, I'm trying to work out why my atmospheric single scattering solution is showing annoyingly off colours. At midday, at height zero, you'd expect an even, light blue sky dome, brightening up at the horizon (mie scattering ignored for now), wheras my simulation produces a reasonable effect near the horizon (but maybe getting ever so slightly reddish), and fading to a dark blue directly overhead. At height >= 1, I get a very bright white band instantly fading to black, with very little of the characteristic bluish fading glow you should see. My method is based on the paper "Real-Time Rendering Of Planets With Atmospheres" (Schafhitzel...), in that I store the results of the standard atmospheric scattering equation (not including rayleigh or mie phase factors, which I apply later in the fragment shader) in a 64x64x64 3d texture, parameterized by height, view direction and sun direction. Upping the sampling rate helps, but not much; I'm currently using 40 samples for each integral. I'll add the code if anybody is interested. The constants I am currently using are: Planet radius: 6360km Atmosphere thickness: 60km Rayleigh coefficients: { 5.8x10-6, 13.5x10-6, 33.1x10-6 } I guess my question is: Has anyone come across this darkening effect before? (appears to be around blue wavelengths?). fwiw, here's the code that calculates the scattering terms:

		/// <summary>
		/// Computes the single scattering equation for a given sun angle, viewer orientation, and height. Stores
		/// the result in a 4-component voxel
		/// </summary>
		private unsafe void ComputeScattering( Vector3 viewDir, Vector3 sunDir, float height, byte* voxel )
		{
			Point3 viewPos = new Point3( 0, height, 0 );
			Point3 viewEnd;
			GetRayAtmosphereIntersection( viewPos, viewDir, out viewEnd );

			Vector3 vecToPt = viewEnd - viewPos;
			Vector3 sampleStep = vecToPt / m_AttenuationSamples;
			float mul = sampleStep.Length * m_InscatterDistanceFudgeFactor;
			if ( mul < 0.00001f )
			{
				voxel[ 0 ] = voxel[ 1 ] = voxel[ 2 ] = voxel[ 3 ] = 0;
				return;
			}
			float* rAccum = stackalloc float[ 3 ];
			float* mAccum = stackalloc float[ 3 ];
			float* rViewOutScatter = stackalloc float[ 3 ];
			float* mViewOutScatter = stackalloc float[ 3 ];
			float* rSunOutScatter = stackalloc float[ 3 ];
			float* mSunOutScatter = stackalloc float[ 3 ];

			Point3 samplePos = viewPos + sampleStep;

			for ( int sampleCount = 1; sampleCount < m_AttenuationSamples; ++sampleCount, samplePos += sampleStep )
			{
				//	Cast a ray to the sun
				Point3 sunPt;
				if ( !GetRayAtmosphereIntersection( samplePos, sunDir, out sunPt ) )
				{	
					continue;
				}

				float sampleHeight = Height( samplePos );
				float pRCoeff = Functions.Exp( sampleHeight * m_InvRH0 ) * mul;	//	m_InvRH0 is 1 / -rayleigh scale height (~8km)
				float pMCoeff = Functions.Exp( sampleHeight * m_InvMH0 ) * mul;	//	m_InvMH0 is 1 / -mie scale height

				//	Calculate (wavelength-dependent) out-scatter terms
				Vector3 viewStep = ( viewPos - samplePos ) / m_AttenuationSamples;
				Vector3 sunStep = ( sunPt - samplePos ) / m_AttenuationSamples;

				CalculateOutScatter( samplePos, sunStep, rSunOutScatter, mSunOutScatter );
				CalculateOutScatter( samplePos, viewStep, rViewOutScatter, mViewOutScatter );

				for ( int i = 0; i < 3; ++i )
				{
					float outScatterR = Functions.Exp( ( -rViewOutScatter[ i ] - rSunOutScatter[ i ] ) );
					float outScatterM = Functions.Exp( ( -mViewOutScatter[ i ] - mSunOutScatter[ i ] ) );
					mAccum[ i ] += pMCoeff * outScatterM;
					rAccum[ i ] += pRCoeff * outScatterR;
				}
			}

			float tR = rAccum[ 0 ] * m_RayleighCoefficients[ 0 ];
			float tG = rAccum[ 1 ] * m_RayleighCoefficients[ 1 ];
			float tB = rAccum[ 2 ] * m_RayleighCoefficients[ 2 ];
			float tA = ( ( mAccum[ 0 ] * m_MieCoefficients[ 0 ] ) + ( mAccum[ 1 ] * m_MieCoefficients[ 1 ] )  + ( mAccum[ 2 ] * m_MieCoefficients[ 2 ] ) ) / 3;

			voxel[ 0 ] = ( byte )Utils.Clamp( tR * 255, 0, 255 );
			voxel[ 1 ] = ( byte )Utils.Clamp( tG * 255, 0, 255 );
			voxel[ 2 ] = ( byte )Utils.Clamp( tB * 255, 0, 255 );
			voxel[ 3 ] = ( byte )Utils.Clamp( tA * 255, 0, 255 );
		}

		private float Height( Point3 pt )
		{
			return Utils.Clamp( pt.DistanceTo( Point3.Origin ) - m_InnerRadius, 0, m_OuterRadius - m_InnerRadius );
		}

		private unsafe void CalculateOutScatter( Point3 startPt, Vector3 step, float* rOutScatter, float* mOutScatter )
		{
			float mul = step.Length;
			Point3 samplePt = startPt;
			float rAccum = 0;
			float mAccum = 0;
			for ( int sample = 0; sample < m_AttenuationSamples; ++sample )
			{
				float samplePtHeight = Height( samplePt );
				float samplePtRCoeff = Functions.Exp( samplePtHeight * m_InvRH0 );
				float samplePtMCoeff = Functions.Exp( samplePtHeight * m_InvMH0 );

				rAccum += samplePtRCoeff * mul;
				mAccum += samplePtMCoeff * mul;

				samplePt += step;
			}
			for ( int i = 0; i < 3; ++i )
			{
				rOutScatter[ i ] = m_RayleighCoefficients[ i ] * rAccum;
				mOutScatter[ i ] = m_MieCoefficients[ i ] * mAccum;
			}
		}

Thanks in advance, coderfish [Edited by - CoderFish on July 1, 2009 6:30:34 PM]
cignox1
cignox1
I've implemented the first part of "A practical analytic model for daylight" in my raytracer and I've seen a similar effect: if the horizon looks ok, then at zenith the sky is too dark. I think that this happens due to the fact that I did not implement most of the paper and that I've not applied Tone Mapping/Gamma correction (I've just started to learn about those so I don't know if it should be done at all)...

One day I must implement the full paper...
Schrompf
Schrompf
My bet goes to gamma correction as well. For starters, try to sqrt() the resulting color and check if it's better that way. I never implemented athmospheric scattering myself, but your descriptions of the differences between expected and resulting colors sound all too familiar - they're the standard signs of physically correct lighting calculations done in a gamma-uncorrected way.
----------
Gonna try that "Indie" stuff I keep hearing about. Let's start with Splatter.
CoderFish
CoderFish
Looks a lot better, thanks guys.

Topic Locked

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

Sign in to reply to this topic.