Jump to content
  • Advertisement
Sign in to follow this  
Viik

Dual Paraboloid shadow mapping and tesselataion issue

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

I was expecting to have issue with tesselation and dual paraboloids mapping before using this technique, but such a worse result was not expected at all. Seams can be easily seen on this screenshot: Dual Paraboloid shadow mapping shaded And it comes with such tesselation: Dual Paraboloid shadow mapping wireframe It's becoming even worse when light is close to shadow receivers. Just for infromation, maybe it's important, i'm using VSM and shadow map resolution is limited to 1024x1024.

Share this post


Link to post
Share on other sites
Advertisement
Hi! Yes, it's very hard to get high quality results. The first thing I'd point out is that your floor shouldn't need to be tesselated at all (unless it's going to be casting on something else).

http://osman.brian.googlepages.com/dpsm.pdf

That paper talks about the simple fix so that you don't need to tesselate receivers (only casters). The basic idea is that you do the WorldSpace -> Paraboloid transformation in the pixel shader during your lighting pass. That avoids having the paraboloid co-ordinates interpolated incorrectly.

You still might have some problems, though ... I can't really tell if that table is going to cast correct shadows. I think it will, but I'd like to see new screen shots after you move the shadow lookup math into the pixel shader. Good luck!

Share this post


Link to post
Share on other sites
Shadow lookup done correctly with transformation inside pixel shader. Issue in generation phase where I simply use HLSL's clip function to cull pixels that dont belong to needed hemisphere, looks like culling should be done using alpha test as in Brabec's paper.
Tesselating casters on hardware is not possible for me as I limited to DX9, actually dont understand their logic - hardware tesselation requires geometric shaders but if you have them you can render to cubemap in one render instead of six, than why one will be using paraboloids, as even for hemisphere light cubemap would be a better solution.
In worst case I'll be using paraboloid only for hemispherical lights, it's much faster than cubemap anyway on DX9.

[Edited by - Viik on November 29, 2008 4:03:03 PM]

Share this post


Link to post
Share on other sites
Yes, I think you should use the alpha-test technique to do the clipping. When we mentioned the hardware tesselation, we were actually talking about Xbox 360. That's still DX9 hardware (no geometry shaders), but the GPU can do automatic tesselation. For PCs, you're right that it doesn't make much sense.

Even with some of the changes you must make, it's definitely faster than using cubemaps!

Share this post


Link to post
Share on other sites
Maybe one point to note as well is that you don't even need to worry about the cracks between paraboloids if you just point one of the paraboloids downward. Then the crack will by somewhere like the equator of your scene, where it will likely be much less noticeable.

Share this post


Link to post
Share on other sites
Quote:
Maybe one point to note as well is that you don't even need to worry about the cracks between paraboloids if you just point one of the paraboloids downward. Then the crack will by somewhere like the equator of your scene, where it will likely be much less noticeable.

That's definately an option. Especially for static lights. Just want to achive more "general" solution.
I'm getting better results with "culling" on shadow lookup phase instead of depth render phase.
Didnt used "alpha" approach like in Brabeck's paper - as I see it requires to store separate alpha on depth render phase. I'm using VSM and that's already consumes G32R32F texture, adding alpha would require 4 channel buffer and two of them would be wasted (32 bit for alpha is too much) and actually two such textures needed. So, I completely droped culling on depth render and did a proper texture lookup on shadow render, choosing proper paraboloid texture. It works quite OK, but there are still small bug:
Tinny bug
"Small black line just under the light" - it's solely because of the choosing right "texture", it's still there with/without blur or VSM.


float3 LightVec = normalize(IN.pos - LightPos);
float3 P = mul(LightVec, (float3x3)ParaboloidBasis);
float myDepth = length(IN.pos - LightPos);
float2 moments;

bool branch = (P.z >= 0.0f); //forward or backward
if(branch)
{
float2 front;
front.x = (P.x / (2*(1 + P.z))) + 0.5;
front.y = 1-((P.y / (2*(1 + P.z))) + 0.5);
float2 forward = tex2D(ShadowSampler, front).xy;
moments = forward;
}
else
{
float2 back;
back.x = (P.x / (2*(1 - P.z))) + 0.5;
back.y = 1-((P.y / (2*(1 - P.z))) + 0.5);
float2 backward = tex2D(ShadowSampler, back).zw;
moments = backward;
}
float VSM = VSMFactor(moments, myDepth);



Quote:
...When we mentioned the hardware tesselation, we were actually talking about Xbox 360. That's still DX9 hardware (no geometry shaders), but the GPU can do automatic tesselation. For PCs, you're right that it doesn't make much sense.
Even with some of the changes you must make, it's definitely faster than using cubemaps!

Didn't realized that it's actually your article ))) Missed a last paragraph where you mention that it's form Xbox 360.
According to your article, correct blurring of paraboloid might be an expensive operation. I used guassian separate blur of 5x5 tap in texture space. If I do it in paraboloid space that would lead to at least 10 vector x matrix multiplications, to get all needed samples.

[Edited by - Viik on December 1, 2008 7:34:43 AM]

Share this post


Link to post
Share on other sites
Haha. I wouldn't worry about "correct blurring". We never implemented that. We used PCF on a previous game, and we're using VSM now, with a regular (texture-space) 5x5 separable gaussian blur. I'm not sure about that black line. Our lookup is done very similar to yours (we have both hemispheres in a single texture, and pick the correct one + lookup in the pixel shader).


Of course, we still have light cracks between the hemispheres, but we always rotate our lights so that the hemispheres point "up" and "down". Most of our lights are above the scene, so it's rare that people can see the crack. It's still on our list of things to debug, although we've tried several times without luck. =(

Share this post


Link to post
Share on other sites
Small black line was because of the black border used in sampler. Now it works like a sharm, except sometimes on depth render stage geometry from back paraboloid projected on front (i'm not using any kind of clipping), but that would be easy to fix just do clipping with small bias.
Thanks again to everybody for your help.

Share this post


Link to post
Share on other sites
Hi Viik,
How did you perform the transformation in the pixel shader?
Are you supposed to just code the world position transformation code in the pixel shader instead of the vertex shader?
When I tried this, the texture just comes out black. Btw, I am still not up to the shadow mapping phase of dual paraboloid (still just testing the reflection mapping) so forgive me if this is not in the correct topic.

Here's my Vertex shader code:


DPOutput DP_VS(float3 pos : POSITION0, float3 normal : NORMAL0, float2 texcoord: TEXCOORD0)
{
DPOutput output = (DPOutput)0;
float4 posWorld = mul(float4(pos,1), World);
float4 viewPos = mul(posWorld, View);
output.Position = mul(float4(pos,1.0f), WorldViewProj);
output.Texcoords = texcoord;
output.Normal = mul(float4(normal,0), (float3x3)WorldInvTrans);
output.WorldPos = posWorld;

output.Position = output.Position/output.Position.w;
output.Position.z = output.Position.z*Direction;
float L = length(output.Position.xyz);
output.Position = output.Position/L;
output.z = output.Position.z;
output.Position.z = output.Position.z + 1;
output.Position.x = output.Position.x/output.Position.z;
output.Position.y = output.Position.y/output.Position.z;
output.Position.z = (L - 0.1f)/(1000-0.1f);
output.Position.w = 1;
return output;
}


Thanks,

Gary

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!