Jump to content
  • Advertisement
Sign in to follow this  
Zombiak

Atmospheric Scattering problem

This topic is 3509 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi. I have problem implementing optical depth approximation technique from this paper http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html Scale() function doesn't work proper or I don't know how to use it proper ;) When I compute myself optical length to the sun and to the camera it works well. Screenshot: http://screenup.pl/?l=W3UQ8EY http://screenup.pl/?l=0KPOG7O It's a bit inaccurate because of per vertex phase function but it doesn't matter. However, when I use O'Neil's approximation function the sun and atmosphere doesn't go reddish (because of wrong outscattering calculation) and there are artifacts. http://screenup.pl/?l=TI0T6J9 It's probably problem with angle what I am passing, but I really don't know what is wrong. This is my shader code, I have left some garbage before removing previous scattering technique.
#include "common_shader.fxh"

float perezY[5],perezx[5],perezy[5];
float perezFx, perezFy, perezFY;

struct VS_INPUT 
{
   float4 Position : POSITION0;

};

struct VS_OUTPUT 
{
   float4 Position : POSITION0;
   float3 Color    : COLOR0;   
};


/*
float perez(float cosTheta, float cosGamma, float gamma, float coef[5])
{
	return (1 + coef[0]*exp(coef[1]/cosTheta)) * (1 + coef[2]*exp(coef[3]*gamma) + coef[4]*cosGamma*cosGamma);
}

float3 perezxyY(float cosSkyZen, float cosSkySun, float SkySun)
{
	float3 ret;

	ret.x = perezFx * perez(cosSkyZen,cosSkySun,SkySun,perezx);
	ret.y = perezFy * perez(cosSkyZen,cosSkySun,SkySun,perezy); 
	ret.z = perezFY * perez(cosSkyZen,cosSkySun,SkySun,perezY); 
	
	return ret;
}

float3 xyYtoRGB(float3 xyY, float expos)
{
	float3 rgb;

	float X,Y,Z;
	X=xyY.z/xyY.y*xyY.x;
	Y=xyY.z;
	Z=xyY.z/xyY.y*(1-xyY.x-xyY.y);

	rgb.x= 3.2404*X - 1.5371*Y - 0.4985*Z;
	rgb.y=-0.9692*X + 1.8759*Y + 0.0415*Z;
	rgb.z= 0.0556*X - 0.2040*Y + 1.0573*Z;

	return float3(1.0-exp(-expos*rgb));
}*/

float g = -0.990;
float ESun = 20;

float3 lambda = float3(0.650,0.570,0.475);

float Kr = 0.0025;
float Km = 0.0010;

float Re = 10.0;
//float atmosphereThickness = 0.025;

float Ra = 10.25;//Re*(1+atmosphereThickness);

float fAtmosphereScale = 4; // 1/(Ra-Re)

float fRayleighScaleDepth = 0.25;

float miePhase(float cosTheta)
{
	return 1.5 * ((1.0-g*g) / (2.0 +g*g)) * (1.0 + cosTheta*cosTheta) / pow(1.0+g*g-2*g*cosTheta,1.5);
}

float rayleighPhase(float cosTheta)
{
	return 0.75+0.75*cosTheta*cosTheta;
}

/*
float2 GetDensityMR(float height)
{
	float alt = (height - Re) * scale;
	return exp(-alt / scaleHeightMR);
}*/

float cameraHeight = 10;//Re; // nie wiem jaka powinna dokladnie byc ta wartosc to ustawiam taka



float raySphereIntersection(float3 sphereCenter, float r, float3 rayOrign, float3 rayDir)
{
   float3 v = rayOrign - sphereCenter;
   float b = dot(v,rayDir);
   float delta = b*b - (dot(v,v) - r*r);
   float sqrtdelta = sqrt(delta);
   float t1 = -b + sqrtdelta;
   float t2 = -b - sqrtdelta;
  
   float nearest;
   if(t2>0)
   {
      if(t1>0)
         nearest=min(t1,t2);
      else
         nearest=t2;
   }
    else
          nearest=t1; 
   
   return nearest;
    
}



float atmosphereDensity(float height)
{
	return exp((Re - height)*fAtmosphereScale/fRayleighScaleDepth);
}

// oneilScale() * atmosphereDensity(height) = optical length: height -> top of atmosphere
float oneilScale(float fCos)
{
	float x = 1.0 - fCos;
	return fRayleighScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
}

float opticalDepth(float3 A, float3 B)
{
	float depth = 0;
	
	float3 dir = B - A;
	float len = length(dir);
	dir/=len;

	float scaledLen = len * fAtmosphereScale;
	int numSamples = 10;
	float sampleLen = scaledLen / numSamples;

	float3 p = A;

	for(int i = 0; i<=numSamples; i++)
	{
		float d = atmosphereDensity(length(p));

		depth+=d*sampleLen;
		
		p+= dir*sampleLen;
	}

	return depth;
}

VS_OUTPUT vs_main( VS_INPUT Input )
{

	VS_OUTPUT Output;

	Input.Position.xyz*=-5000;
	
	//float cosSkySun = saturate(dot(toSky,vSunDir.xyz));
	//float SkySun = acos(cosSkySun); // Y
	//float cosSkyZen = saturate(toSky.y);

	
	float3 position = float3(0,Re,0);
	float3 rayDir = normalize(Input.Position.xyz);
	float positionNormalized = normalize(position);
	float rayDist = raySphereIntersection(float3(0,0,0),Ra,position,rayDir);

	float cosSkySun = saturate(dot(rayDir,vSunDir.xyz));
	
	int numSamples = 10;

	float sampleLen = rayDist/numSamples;

	//float totalMie = 0;
	float3 totalScattering = 0;

	float sampleScaled = sampleLen *fAtmosphereScale;

	float3 samplePoint = position;

	for(int i=0;i<=numSamples;i++)
	{
		

		float height = length(samplePoint);
		
		float density = atmosphereDensity(height);
		float sampleNormalized = samplePoint / height;
		//float sunDepth = density*oneilScale(dot(sampleNormalized,vSunDir.xyz));
		//float cameraDepth = atmosphereDensity(cameraHeight)*oneilScale(dot(positionNormalized,rayDir))
		//	- density*oneilScale(dot(sampleNormalized,rayDir));
		
		float cameraDepth = opticalDepth(position,samplePoint);

		float3 sunAtm = samplePoint + vSunDir*raySphereIntersection(float3(0,0,0),Ra,samplePoint,vSunDir);
		
		float sunDepth = opticalDepth(samplePoint,sunAtm);

		totalScattering+= density*sampleScaled
			*exp(
			//(-cameraDepth-sunDepth)
			-density*(
					oneilScale(dot(sampleNormalized,vSunDir.xyz))
					-oneilScale(dot(sampleNormalized,rayDir))
				)
			*4*Pi*(pow(lambda,-4)*Kr+Km))
			;
		samplePoint+=rayDir*sampleScaled;
	}


	Output.Color=
	totalScattering
	*(1*
	miePhase(-cosSkySun)*Km*20
	+rayleighPhase(-cosSkySun)
	*pow(lambda,-4)*Kr*20//;rayDist
	)
	;




	//float3 xyY = perezxyY(cosSkyZen,cosSkySun,SkySun);
	//Output.Color= applyHaze(float3(0,0,0),cosSkySun,rayDist);
	//float4(xyYtoRGB(xyY,0.0001),1);

	Input.Position.xz+=vViewPosition.xz;
	Output.Position = mul( Input.Position, matViewProjection );


	return( Output );
   
}

float4 ps_main(float3 Color    : COLOR0) : COLOR0
{
   return float4(Color,1);
   
}

technique Terrain
{
	pass Pass1
	{
		VertexShader = compile vs_3_0 vs_main();
		PixelShader = compile ps_3_0 ps_main();
	}
}

Sorry for my English, it's still doesn't well enough, but I hope you can understand my problem ;)

Share this post


Link to post
Share on other sites
Advertisement
You should check out this thread to see if the answer you are looking for is in there :

http://www.gamedev.net/community/forums/topic.asp?topic_id=461747

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!