Sign in to follow this  
Zombiak

Atmospheric Scattering problem

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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this