I'm currently porting O'neils article from GPU Gems 2 to HLSL. I was wondering if anyone can spot anything in here that would cause the atmosphere to render as a thick white band when the camera is looking at the atmosphere from space?
CONSTANTS FROM C Code:
_samples = 3;
_Kr = 0.0025f;
_Kr4PI = (_Kr*4.0f*3.141592),
_Km = (0.0015f),
_Km4PI = (_Km*4.0f*3.141592),
_eSun = (15.0f);
_g = (-0.95f);
_g2 = (_g*_g);
_exposure = (10.0f);
_innerRadius = (150);
_outerRadius = (153.75);
_scale = 1.0f / (_outerRadius - _innerRadius);
_invScaleDepth = 1.0 / 0.25;
_rayleighScaleDepth = 0.25f;
_mieScaleDepth = 0.1f;
_wavelength.x = 0.650f; // 650 nm for red
_wavelength.y = 0.570f; // 570 nm for green
_wavelength.z = 0.475f; // 475 nm for blue
_wavelength.w = 1.0f;
_wavelength4.x = powf (_wavelength.x, 4.0f);
_wavelength4.y = powf (_wavelength.y, 4.0f);
_wavelength4.z = powf (_wavelength.z, 4.0f);
_wavelength4.w = 1;
_invWavelength =
D3DXVECTOR4 (
1.0f / _wavelength4.x,
1.0f / _wavelength4.y,
1.0f / _wavelength4.z, 1
0);
FX Code:
float4x4 WorldViewProj: WORLDVIEWPROJECTION
<
string UIWidget = "none";
string ScriptClass = "object";
string ScriptOrder = "standard";
string ScriptOutput = "none";
string ToString = "WORLDVIEWPROJECTION";
> = 0.0;
float Script : STANDARDSGLOBAL
<
string UIWidget = "none";
string ScriptClass = "object";
string ScriptOrder = "standard";
string ScriptOutput = "color";
string ToString = "FlxAtmosphere";
> = 0.0;
float4 invWavelength
<
string UIWidget = "none";
string ScriptClass = "object";
string ScriptOrder = "standard";
string ScriptOutput = "none";
string ToString = "INVWAVELENGTH";
> = 0;//
float4 cameraPosition : EYELOCATION
<
string UIWidget = "none";
string ScriptClass = "object";
string ScriptOrder = "standard";
string ScriptOutput = "none";
string ToString = "EYELOCATION";
> = 0.0;
float4 lightDirection : LIGHTDIRECTION
<
string UIWidget = "none";
string ScriptClass = "object";
string ScriptOrder = "standard";
string ScriptOutput = "none";
string ToString = "LIGHTDIRECTION";
> = 0.0;
float cameraHeight; // The camera's current height
float cameraHeight2; // fCameraHeight^2
float outerRadius; // The outer (atmosphere) radius
float outerRadius2; // fOuterRadius^2
float innerRadius; // The inner (planetary) radius
float innerRadius2; // fInnerRadius^2
float krESun; // Kr * ESun
float kmESun; // Km * ESun
float kr4PI; // Kr * 4 * PI
float km4PI; // Km * 4 * PI
float scale; // 1 / (fOuterRadius - fInnerRadius)
float scaleDepth = 0.25f; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
float scaleOverScaleDepth = 6; // fScale / fScaleDepth
float g;
float g2;
struct vpconn
{
float4 Position : POSITION;
float3 t0 : TEXCOORD0;
float3 c0 : COLOR; float3 c1 : COLOR1;
};
struct vsconn
{
float4 rgbColor : COLOR0;
//float4 depthColor : COLOR1;
};
// The scale equation calculated by Vernier's Graphical Analysis
float expScale (float fCos)
{
float x = 1.0 - fCos;
return scaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
}
// Calculates the Mie phase function
float getMiePhase(float fCos, float fCos2, float g, float g2)
{
return 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos2) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
}
// Calculates the Rayleigh phase function
float getRayleighPhase(float fCos2)
{
return 1.0;
//return 0.75 + (0.75*fCos2);
}
// Returns the near intersection point of a line and a sphere
float getNearIntersection(float3 v3Pos, float3 v3Ray, float fDistance2, float fRadius2)
{
float B = 2.0 * dot(v3Pos, v3Ray);
float C = fDistance2 - fRadius2;
float fDet = max(0.0, B*B - 4.0 * C);
return 0.5 * (-B - sqrt(fDet));
}
// Returns the far intersection point of a line and a sphere
float getFarIntersection(float3 v3Pos, float3 v3Ray, float fDistance2, float fRadius2)
{
float B = 2.0 * dot(v3Pos, v3Ray);
float C = fDistance2 - fRadius2;
float fDet = max(0.0, B*B - 4.0 * C);
return 0.5 * (-B + sqrt(fDet));
}
vpconn
AtmosphereFromSpaceVS(float4 vPos : POSITION,
float3 vNormal : NORMAL,
float2 vTexCoord0 : TEXCOORD0 )
{
float3 ray = vPos.xyz - cameraPosition.xyz;
float far = length (ray);
ray /= far;
float near = getNearIntersection (cameraPosition, ray,
cameraHeight2, outerRadius2);
float3 start = cameraPosition + ray * near;
far -= near;
float startAngle = dot (ray, start) / outerRadius;
float startDepth = exp (-1.0 / scaleDepth);
float startOffset = startDepth * expScale (startAngle);
float sampleLength = far / 3.0f;
float scaledLength = sampleLength * scale;
float sampleRay = ray * sampleLength;
float samplePoint = start + sampleRay * 0.5f;
float3 frontColor = float3 (0,0,0);
for (int i = 0; i < 3; i++)
{
float height = length (samplePoint);
float depth = exp (scaleOverScaleDepth * (innerRadius - height));
float lightAngle = dot (lightDirection, samplePoint) / height;
float cameraAngle = dot (ray, samplePoint) / height;
float scatter = (startOffset + depth * (
expScale (lightAngle) - expScale (cameraAngle)));
float3 attenuate = exp (-scatter * (invWavelength.xyz * kr4PI + km4PI));
frontColor += attenuate * (depth * scaledLength);
samplePoint = samplePoint + sampleRay;
}
vpconn OUT;
OUT.t0 = cameraPosition.xyz - vPos.xyz;
OUT.Position = mul(vPos, WorldViewProj);
OUT.c0.xyz = frontColor * (invWavelength.xyz * krESun);
OUT.c1.xyz = frontColor * kmESun;
return OUT;
}
vsconn
AtmosphereFromSpacePS(vpconn IN)
{
vsconn OUT;
float cos = dot (lightDirection, IN.t0) / length (IN.t0);
float cos2 = cos * cos;
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + cos*cos) /
pow(1.0 + g2 - 2.0*g*cos, 1.5);
OUT.rgbColor.rgb = getRayleighPhase(cos2) * IN.c0 + fMiePhase *
IN.c1; //getRayleighPhase (cos2) * IN.c0 +
OUT.rgbColor.a = OUT.rgbColor.b;
return OUT;
}
technique AtmosphereFromSpace
{
pass P0
{
//AlphaBlendEnable = true;
CullMode = CW;
VertexShader = compile vs_3_0 AtmosphereFromSpaceVS();
PixelShader = compile ps_2_a AtmosphereFromSpacePS();
}
}
EDIT: Please remember to use 'source' tags in future!
[Edited by - jollyjeffers on August 12, 2007 9:08:41 AM]