sensate 576 Report post Posted August 11, 2007 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] 0 Share this post Link to post Share on other sites
AvengerDr 751 Report post Posted August 12, 2007 Sorry, can't help you right now, but... from looking at your code it seems like you are trying to do a shader to render a planet's atmosphere from space. Is that right?? 0 Share this post Link to post Share on other sites
jollyjeffers 1570 Report post Posted August 12, 2007 Static code analysis for this sort of thing is unlikely to be the right way to go about it. You need to do some runtime debugging via PIX.Use the 'pixel history' feature to examine one of these white pixels and see what intermediary values were used. I'd take a guess at an FP exception (e.g. divide by zero) causing a +INF result which eventually gets clamped to white when written to the frame buffer. If you can identify this you just back-track through the arithmetic to find out the special case - maybe a perpendicular view vector generates a 0.0 dot product result or something like that...hthJack 0 Share this post Link to post Share on other sites
sensate 576 Report post Posted August 13, 2007 Thanks for taking the time!It turns out that I'm an idiot... and that I had two variables that should have been float3's instead of floats...On the flip side, I found that I detest working with PIX. Well actually, I detest working with DirectX in debug.Thanks for pointing me to it though. (I knew of it, but I didn't realize that the debugging facilities had progressed to the point where shaders could be debugged... cool stuff. 0 Share this post Link to post Share on other sites
AvengerDr 751 Report post Posted August 14, 2007 I tried to implement the code from the original poster using Rendermonkey (I'm in the midst of some refactoring so I didn't have the chance to try it in my engin) but all I'm getting is a white sphere. There's probably some mathematical instruction that's making all pixels go white. I think I fixed the float3/float issue from the OP (I believe those two variables were sampleRay and samplePoint) but there's still something amiss.So I have some questions about all this1) Does the original sphere need to have something "particular"? I see the code uses in the vertex shader signature texture Coordinates and Normals, but they don't seem to be used in the code (vNormal and vTexcoord). Or any sphere will do?2) Is there a relationship between the camera position and the effect before something will show up? I mean, for a sphere of radius of 1 unit, one should be at at least x times the radius away..?3) About the lightDirection vector.. does that mean the position of the light source (ie its position in object space) or the vector from its position to the sphere? (vObjectPosition - vLightPosition if I'm not mistaken)4) FInally, what should I see when everything is working right? I suppose that an all-white sphere doesn't mean that it's working right. :D5) Why won't it work :DThanks in advance! 0 Share this post Link to post Share on other sites