# Atmospheric Scattering problem

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

## 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));
//	- density*oneilScale(dot(sampleNormalized,rayDir));

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

float sunDepth = opticalDepth(samplePoint,sunAtm);

totalScattering+= density*sampleScaled
*exp(
-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
{
}
}


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

##### Share on other sites
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

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 12
• 30
• 9
• 16
• 12