Sean O'Neils atmospheric scattering

Started by
13 comments, last by dealeer 11 years, 4 months ago
You might want to think about working from the most current version of his shaders (poke around in 'downloads'), rather than the dated, and somewhat badly-commented version in GPU Gems...

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Advertisement

Is the orange day/night transition in your renders a result of O'Neils shader, or something that you are doing?


It is a result of O'Neil's shaders.

I can't find any obvious mistakes in your code except for:

[color=#000000]float4 [color=#660066]Color0[color=#000000] [color=#666600]:[color=#000000] COLOR0[color=#666600];
[color=#000000]float4 [color=#660066]Color1[color=#000000] [color=#666600]:[color=#000000] COLOR1[color=#666600];

You should pass these values as TEXCOORD's, because directx clamps COLOR to the [0, 1] range.
This should only cause minor artifacts though.


You might want to think about working from the most current version of his shaders (poke around in 'downloads'), rather than the dated, and somewhat badly-commented version in GPU Gems...


Thank you for pointing this out! I had no idea.

You might want to think about working from the most current version of his shaders (poke around in 'downloads'), rather than the dated, and somewhat badly-commented version in GPU Gems...

The thing is, I am!
I have started the SkyFromSpace shader from scratch about 6 times now, once from the GPU Gems article, once from the current version, once from the article in nvidia FX Composer, trying to debug it, again from the current version in fx composer, once from someone else's source code on here, and once from Hyunkel's code here.

I figured out why I didn't get the orange transition. Before I got the lightScale value right, the whole sphere was lit up so I multiplied the resulting diffuse by the lightAngle to make the far side of the planet dark. Now that the lightScale works correctly though, it was fading the diffuse out before the transition.
Now that it's got the right value, the far side of the planet turns dark on it's own.

I'm kind of clueless about the SkyFromSpace shader though...I guess I will take another stab at it sometime.
C:\FxComposer.jpg
hello,
I come here baring a cry for help. I needed an atmosphere shader for the little project I am working on. so I convert the SkyFormSpace shader in the book GPU gems 2- Chapter 16, Accurate Atmospheric Scattering written by Sean O'Neil to SkyFormSpace.fx. I want to see the atmosphere effect in the software FX Composer . but the result is incorrect?


the effect in FxComposer:
original_T9ix_6f2800000af1118e.jpg

and the effect in my project:
original_VJuS_5da900000ae1118f.jpg

Here is the shader code i'm using:

// SkyFromSpace - Author: Sean O'Neil - Copyright (c) 2004 Sean O'Neil
//The output of this vertex shader
struct vertout
{
float4 pos : POSITION; // Transformed vertex position
float4 c0 : COLOR0; // The Rayleigh color
float4 c1 : COLOR1; // The Mie color
float3 t0 : TEXCOORD0;
};
//The number of sample points taken along the ray
const int nSamples = 2;
const float fSamples =2.0;
//The scale depth (the altitude at which the average atmospheric density is found)
const float fScaleDepth = 0.25;
const float fInvScaleDepth = 4.0;
//The scale equation calculated by Vernier's Graphical Analysis
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(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));
}
//uniform float4x4 gl_ModelViewProjectionMatrix;
uniform float4x4 worldViewProj: WorldViewProjection;
uniform float3 v3CameraPos={0.0,0.0,25};// The camera's current position
uniform float3 v3LightPos={0.0,0.0,1}; // The direction vector to the light source
uniform float fOuterRadius=10.15f; // The outer (atmosphere) radius
uniform float fInnerRadius=10.0f; // The inner (planetary) radius
uniform float red = 0.650f; // 650 nm for red
uniform float green = 0.570f; // 570 nm for green
uniform float blue = 0.475f; // 475 nm for blue
uniform float Kr = 0.0025f;
uniform float Km = 0.0015f;
uniform float PI = 3.14159f;
uniform float ESun = 15.0f;
vertout v_SkyFormSpace(float4 gl_Vertex : POSITION)
{
float3 v3InvWavelength={1.0/pow(red, 4.0f),1.0/pow(green, 4.0f),1.0/pow(blue, 4.0f)};
float fCameraHeight=sqrt(v3CameraPos.x*v3CameraPos.x+v3CameraPos.y*v3CameraPos.y+v3CameraPos.z*v3CameraPos.z);
float fCameraHeight2=fCameraHeight*fCameraHeight;

float fOuterRadius2=fOuterRadius*fOuterRadius;
float fInnerRadius2=fInnerRadius*fInnerRadius;

float fKrESun=Kr * ESun;
float fKmESun=Km * ESun;
float fKr4PI=Kr * 4 * PI;
float fKm4PI=Km * 4 * PI;
float fScale=1.0 / (fOuterRadius - fInnerRadius);
float fScaleOverScaleDepth=fScale / fScaleDepth;

// 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 = gl_Vertex.xyz;
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(-1.0 / fScaleDepth);
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 fCameraAngle = 1.0;
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
vertout OUT;
OUT.pos = mul(gl_Vertex,worldViewProj);
OUT.c0.rgb = v3FrontColor * (v3InvWavelength * fKrESun);
OUT.c1.rgb = v3FrontColor * fKmESun;
OUT.t0 = v3CameraPos - v3Pos;
return OUT;
}
//uniform float3 v3LightPos;
uniform float g=-0.95;
uniform float g2=0.9025;
float4 p_SkyFormSpace(in float4 c0 : COLOR0,
in float4 c1 : COLOR1,
in float3 v3Direction : TEXCOORD0
) : COLOR
{
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);
float fCos2 = fCos*fCos;
float4 color = getRayleighPhase(fCos2) * c0 + getMiePhase(fCos, fCos2, g, g2) * c1;
color.a = color.b;
return color;
}
technique technique0 {
pass p0 {
CullMode = None;
VertexShader = compile vs_3_0 v_SkyFormSpace();
PixelShader = compile ps_3_0 p_SkyFormSpace();
}
}



If anyone could help me with a fix or have some advice to help me solve the problem, it will be greatly appreciated.

This topic is closed to new replies.

Advertisement