# Atmospheric Scattering XNA 4.0

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

## Recommended Posts

Hello

Anyone out there who could help me..

[img]https://dl.dropbox.com/u/19373509/t/xxa.png[/img]

[CODE]
float4x4 World;
float4x4 View;
float4x4 Projection;
float seaLevel;

float Km = 0.0025f;
float Kr = 0.0015f;
float ESun = 20.0f;

float3 v3InvWavelength = float3(
1.0f / pow(0.650f, 4),
1.0f / pow(0.570f, 4),
1.0f / pow(0.475f, 4)
);

// The number of sample points taken along the ray
static const int nSamples = 2;
static const float fSamples = (float)nSamples;
// Gravity
static const float g = -0.99f;
static const float g2 = 0.81f;

float3 v3CameraPos; // The camera's current position
float3 v3LightPos; // The direction vector to the light source

//float3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
float fCameraHeight; // The camera's current height
float fCameraHeight2; // fCameraHeight^2

float fKrESun = (0.0015f * 10.0f); // Kr * ESun
float fKmESun = (0.0025f * 10.0f);; // Km * ESun

float fKr4PI = 0.0015f * 4.0f * 3.14159265;
float fKm4PI = 0.0025f * 4 * 3.14159265; // Km * 4 * PI

float fScaleDepth = 0.25f; // The scale depth (the altitude at which the average atmospheric density is found)
float fInvScaleDepth = 1.0f / 0.25f; // 1 / fScaleDepth
float fScale = 1.0f / (1.4f - 1.0f);
float fScaleOverScaleDepth = (1.0f) / ( 1.0f / 0.25f); // fScale / fScaleDepth

float scale(float fCos)
{
float x = 1.0 - fCos;
return fScaleDepth * 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(abs(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));
}

{
float4 Position : POSITION0;
float3 PositionWS : TEXCOORD0;
};

{
float4 Position : POSITION0;
float3 PositionWS : TEXCOORD0;
};

{

output.PositionWS = input.Position;

float4 worldPosition = mul(input.Position, World);
worldPosition = float4( normalize(worldPosition.xyz) * 6918.75f, 1);

float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
return output;
}

{

// Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere)
float3 v3Pos = input.PositionWS;
float3 v3Ray = v3Pos - v3CameraPos;
float fFar = length(v3Ray);
v3Ray /= fFar;

// Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere)
float fNear = getNearIntersection(v3CameraPos, v3Ray, fCameraHeight2, fOuterRadius2);

// Calculate the ray's start and end positions in the atmosphere, then calculate its scattering offset
float3 v3Start = v3CameraPos + v3Ray * fNear;
fFar -= fNear;
float fStartAngle = dot(v3Ray, v3Start) / fOuterRadius;
float fStartDepth = exp(-fInvScaleDepth);
float fStartOffset = fStartDepth*scale(fStartAngle);

// Initialize the scattering loop variables
float fSampleLength = fFar / fSamples;
float fScaledLength = fSampleLength * fScale;
float3 v3SampleRay = v3Ray * fSampleLength;
float3 v3SamplePoint = v3Start + v3SampleRay * 0.5;

// Now loop through the sample rays
float3 v3FrontColor = float3(0.0, 0.0, 0.0);
for(int i=0; i<nSamples; i++)
{
float fHeight = length(v3SamplePoint);
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight;
float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;
float fScatter = (fStartOffset + fDepth*(scale(fLightAngle) - scale(fCameraAngle)));
float3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
v3SamplePoint += v3SampleRay;
}

// Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
float3 c0 = v3FrontColor * (v3InvWavelength * fKrESun);
float3 c1 = v3FrontColor * fKmESun;
float3 v3Direction = v3CameraPos - v3Pos;
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);
float fCos2 = fCos*fCos;
float3 color = getRayleighPhase(fCos2) * c0 + getMiePhase(fCos, fCos2, g, g2) * c1;
float4 AtmoColor = float4(color, color.b);
return AtmoColor;
}

//############# Technik #############
technique Technique1
{
pass Pass1
{
CullMode = ccw;
}
}
[/CODE]

And here the Sphere.cs:

[CODE]
public class ScatteringSphere
{
private GraphicsDevice device;
private VertexBuffer vb;
private IndexBuffer ib;
private Effect effect;
private static int size = 128;
Matrix[] rotation = new Matrix[6];
Vector3 lightPos;

public ScatteringSphere(GraphicsDevice device)
{
this.device = device;

CreateSphere();

rotation[1] = Matrix.CreateTranslation(Vector3.Up);

}

private void CreateSphere()
{
VertexPositionColor[] vertices = new VertexPositionColor[size * size];
for (int z = 0; z < size; z++)
for (int x = 0; x < size; x++)
vertices[x + z * size] = new VertexPositionColor(new Vector3(MathHelper.Lerp(-1, 1, (float)x / (size - 1)), 0, MathHelper.Lerp(-1, 1, (float)z / (size - 1))), Color.Aquamarine);

vb = new VertexBuffer(device, typeof(VertexPositionColor), size * size, BufferUsage.WriteOnly);
vb.SetData<VertexPositionColor>(vertices);

ushort[] indices = new ushort[(size - 1) * (size - 1) * 6];
int i = 0;
for (int z = 0; z < size - 1; z++)
for (int x = 0; x < size - 1; x++)
{
ushort upperleft = (ushort)(z * size + x);
ushort upperright = (ushort)(upperleft + 1);
ushort lowerleft = (ushort)(upperleft + size);
ushort lowerright = (ushort)(lowerleft + 1);

indices[i++] = upperleft;
indices[i++] = upperright;
indices[i++] = lowerleft;

indices[i++] = lowerleft;
indices[i++] = upperright;
indices[i++] = lowerright;
}

ib = new IndexBuffer(device, IndexElementSize.SixteenBits, indices.Length, BufferUsage.WriteOnly);
ib.SetData<ushort>(indices);

}

public void Draw(FreeCam cam)
{
device.SetVertexBuffer(vb);
device.Indices = ib;

lightPos = new Vector3(0.5f, 0.5f, -0.5f);
lightPos.Normalize();

effect.Parameters["seaLevel"].SetValue(6750);
effect.Parameters["View"].SetValue(Manager.cam.View);
effect.Parameters["Projection"].SetValue(Manager.cam.Projection);
effect.Parameters["v3CameraPos"].SetValue(Manager.cam.Position);
effect.Parameters["v3LightPos"].SetValue(lightPos);
effect.Parameters["fCameraHeight"].SetValue(Manager.cam.Position.Length());
effect.Parameters["fCameraHeight2"].SetValue(Manager.cam.Position.LengthSquared());

effect.Parameters["World"].SetValue(rotation[0]);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, size * size, 0, (size - 1) * (size - 1) * 6 / 3);
}

effect.Parameters["World"].SetValue(rotation[1]);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, size * size, 0, (size - 1) * (size - 1) * 6 / 3);
}

effect.Parameters["World"].SetValue(rotation[2]);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, size * size, 0, (size - 1) * (size - 1) * 6 / 3);
}

effect.Parameters["World"].SetValue(rotation[3]);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, size * size, 0, (size - 1) * (size - 1) * 6 / 3);
}

effect.Parameters["World"].SetValue(rotation[4]);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, size * size, 0, (size - 1) * (size - 1) * 6 / 3);
}

effect.Parameters["World"].SetValue(rotation[5]);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, size * size, 0, (size - 1) * (size - 1) * 6 / 3);

}

}

}
[/CODE]

AA Edited by montify