Hello,

I'm trying to implement Nvidias Screen Space Fluid Rendering in Ogre using Direct3D9 as my rendering system. (http://developer.download.nvidia.com/presentations/2010/gdc/Direct3D_Effects.pdf for slides and https://www.google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDoQFjAA&url=http%3A%2F%2Fciteseerx.ist.psu.edu%2Fviewdoc%2Fdownload%3Fdoi%3D10.1.1.157.909%26rep%3Drep1%26type%3Dpdf&ei=dlrsUJX6Jq364QSdxIHgAg&usg=AFQjCNEXlV2bFFL0uSrDofS65HAHbtpUHg&sig2=02fSfNNvdlQEO6Pjq2LNQA&bvm=bv.1357316858,d.Yms for paper).

I got my billboard quad particles and using a shader they look like spheres. I save the depth from those spheres in a texture.

At the next step I have to blur the depth.

Now I put this blurred texture on a screen filling quad and let the next shader run on it.

Now I have to create the normals at this point. To get the normals I have to calculate the view-space coordinates from the depth and texture coordinates (see slide 18).

My problem is the mysterious uvToEye-function.

I found some code to recalculate the coordinates here: http://mynameismjp.wordpress.com/2009/03/10/reconstructing-position-from-depth/ but it doesn't work (all I seem to get is (0,0,0) for every point).

This is my code: I skipped the blur-step since I figured there is no need to blur the depth before I cant calculate normals from it.

My vertex shader for depth and making the billboardquads spherical:

struct VertexIn { float4 pos : POSITION; float2 texco : TEXCOORD0; }; struct VertexOut { float4 pos : POSITION; float2 texco : TEXCOORD0; float3 eyeSpacePos : TEXCOORD1; }; struct PixelInput { float2 texco : TEXCOORD0; float3 eyeSpacePos : TEXCOORD1; }; struct PixelOutput { float4 color : COLOR0; }; VertexOut mainVS( VertexIn input, uniform float4x4 worldViewProj_m, uniform float4x4 worldView_m, uniform float sphereRadius ) { VertexOut output = (VertexOut)0; input.pos.y += sphereRadius; //partikel nicht im Boden versinken lassen output.pos = mul( worldViewProj_m, input.pos ); output.texco = input.texco; output.eyeSpacePos = mul(worldView_m, input.pos).xyz; return output; } PixelOutput mainPS(PixelInput input, uniform float4x4 projMatrix, uniform float sphereRadius ) { PixelOutput output = (PixelOutput)0; // calculate eye-space sphere normal from texture coordinates float3 N; N.xy = input.texco*2.0-1.0; float r2 = dot(N.xy, N.xy); if (r2 > 1.0) discard; // kill pixels outside circle N.z = sqrt(1.0 - r2); // calculate depth float4 pixelPos = float4(input.eyeSpacePos + N*sphereRadius, 1.0); //approximation of a sphere float4 clipSpacePos = mul(projMatrix,pixelPos); float fragDepth = clipSpacePos.z / clipSpacePos.w; output.color.r = fragDepth; return output; }

And this is my shader for calculating the normals:

struct VertexIn { float4 pos : POSITION; float2 texco : TEXCOORD0; }; struct VertexOut { float4 pos : POSITION; float2 texco : TEXCOORD0; }; struct PixelInput { float2 texco : TEXCOORD0; }; struct PixelOutput { float4 color : COLOR0; }; VertexOut mainVS(VertexIn input, uniform float4x4 worldViewProj_m) { VertexOut output = (VertexOut)0; output.pos = mul( worldViewProj_m, input.pos ); output.texco = input.texco; return output; } float3 uvToEye(float2 texCoord, float depth, float4x4 iP_m){ // Get x/w and y/w from the viewport position float x = texCoord.x * 2.0 - 1.0; float y = (1 - texCoord.y) * 2.0 - 1.0; //float y = texCoord.y * 2.0 - 1.0; float4 clipPos = float4(x , y, depth, 1.0f); // Transform by the inverse projection matrix //float4 viewPos = mul(clipPos, iP_m); float4 viewPos = mul(iP_m , clipPos); // Divide by w to get the view-space position return viewPos.xyz / viewPos.w; } PixelOutput mainPS(PixelInput input, uniform sampler depthTex: register(s0), uniform float4x4 invProj_m) { PixelOutput output = (PixelOutput)0; // read eye-space depth from texture float depth = tex2D(depthTex, input.texco).r; // calculate eye-space position from depth float texelSize = 0.0001; // correct value? // calculate differences float3 ddx1 = uvToEye(input.texco + float2(texelSize, 0), tex2D(depthTex, input.texco + float2(texelSize, 0)).r, invProj_m) - posEye; float3 ddx2 = posEye - uvToEye(input.texco + float2(-texelSize, 0), tex2D(depthTex, input.texco + float2(-texelSize, 0)).r, invProj_m); ddx1 = -ddx2 + ddx1; if (abs(ddx1.z) > abs(ddx2.z)) { ddx1 = ddx2; } float3 ddy1 = uvToEye(input.texco + float2(0, texelSize), tex2D(depthTex, input.texco + float2(0, texelSize)).r, invProj_m) - posEye; float3 ddy2 = posEye - uvToEye(input.texco + float2(0, -texelSize), tex2D(depthTex, input.texco + float2(0, -texelSize)).r, invProj_m); ddy1 = -ddy2 + ddy1; if (abs(ddy2.z) < abs(ddy1.z)) { ddy1 = ddy2; } // calculate normal float3 n = cross(ddx1, ddy1); n = normalize(n); //output.color = float4(posEye, 1.0); // for testing, results in a black screen output.color = float4(n,1); return output; }

I hope someone here can tell me what I'm doing wrong and what is the right way to do it.

Regards,

Kilian