Sign in to follow this  
Tom KQT

Using tex2Dproj for shadows

Recommended Posts

Hello, I have working shadow mapping in my application, using the tex2D HLSL function. But as I'm still hearing everywhere that there is something like a HW PCF on nVidia cards, which is applied when you use tex2Dproj function, and that this function automatically does the depth comparison as well, for example (http://www.mpi-inf.mpg.de/departments/irg3/ws0405/cg/rcomp/23/index.html):
Quote:
...instead of returning a texture color, tex2Dproj returns a value representing shadow coverage. The underlying hardware implementation automatically recognizes when a texture is a depth texture (instead of a color texture) and performs the shadow map comparison instead of an ordinary texture fetch.
I'm trying to change my shaders. But I still cannot work out what to pass as the second argument of the tex2Dproj function do make the depth comparison and shadow value computation. Could somebody please be so kind and try to explain it to me? Which light related matrices I must multiply with what etc. I've searched the web a lot, my head is going to explode soon, but I found only some articles about this, never fully complete (no FULL example code), each of them different and I didnt manage to work it out as it's hard to guess anything from a matrix name like matShadow etc. Thank you very much in advance With respect, Tom PS: Dunno if this is important but I'm using directional light so my light camera projection matrix is orthogonal.

Share this post


Link to post
Share on other sites
I guess I got the projective texturing working, but as you can see on the picture it just simply projects the shadow map on the scene while it should automatically do the depth comparing (and a small PCF which of course is there neither although I use bilinear filtering).

How do I "tell" the GC that I'm doing shadow mapping and not just normal texture projection?
I know how to do the depth comparing myself, also how to do PCF, but I would like to see the GC do it for me using its HW soft shadows ;) (I don't care that it works only on nVidia cards.)

This is a screenshot from a simple testing application and the ground box is the only one who receives shahows (or better said "should receive shadows")

Share this post


Link to post
Share on other sites
tex2Dproj doesn't do anything like what you are trying to get it to do. It simply projects the texture. You need to write a shader that does the comparison yourself, it will use tex2Dproj but you'll do some sort of depth comparison manually.

Share this post


Link to post
Share on other sites
Are you really sure?

Quote:

quote from link
When we do a projective texture lookup on a shadow map, the hardware automatically takes care of the comparison for you: the tex2Dproj function returns a value that represents how "lit" the current pixel would he. That is, the tex2Dproj function returns a four-component vector of the form (c, c, c, 1), where c is 0 if the pixel is in shadow, and 1 if the pixel is lit. You can then treat this vector as a color. If bilinear texture filtering is enabled, c will range from 0 to 1 instead of being restricted to just the two values. Filtering is useful along the shadow boundaries, where the transition between being fully occluded to fully lit takes place. In these situations, the filtering helps make the shadow look softer, and reduces edge aliasing (jaggedness).


Also look at the code fragments on this GPU Gems page chapter 11
they also use tex2Dproj and there is no mark of any comparison in the code.
And also here:

float shadow = tex2Dproj(Shadow, ShadowUV).x;
// Modify the light color so that it blends with the shadow color
// in the shadow areas
float3 mixedLightColor = lerp(ShadowColor, Light.color, shadow);

which is from another GPU Gems page chapter 10 (this one actually has a more complete code and it was my best reference, but it still doesn't say everything).

There can be found many other remarks about this feature on the internet
(link), most of them are about OpenGL tho.

Share this post


Link to post
Share on other sites
Yes. That article is wrong. And in the GPU gems article, they aren't technically using shadow maps, they are using textures that look like shadows when projected. What you have is a depth map, not a shadow texture, so to turn it into a shadow texture that you can project onto the scene you need to do a comparison with the real depth to see whether the pixel is in shadow.

If you want soft shadows you have to compute your shadow texture (not depth map) and then use a sampling pattern larger than one pixel.

Share this post


Link to post
Share on other sites
Quote:
Original post by AnAss
Yes. That article is wrong.

You mean all those articles all over the internet are wrong?

Quote:
Original post by AnAss
And in the GPU gems article, they aren't technically using shadow maps, they are using textures that look like shadows when projected.

Did you look at both the GPU Gems articles? This one ch11 is IMHO (but only IMHO) clearly about shadow maps with depth comparison. The code fragments are not very clear, but there is no "manual" depth comparison and it doesn't seem it would be possible to use it in any corresponding unshown code as it produces a shadowCoef computed from multiple samples (which would mean they would be comparing average of multiple depths and that would not work). :O

Quote:
Original post by AnAss
What you have is a depth map, not a shadow texture, so to turn it into a shadow texture that you can project onto the scene you need to do a comparison with the real depth to see whether the pixel is in shadow.

If you want soft shadows you have to compute your shadow texture (not depth map) and then use a sampling pattern larger than one pixel.

Yep, I know this, as I said in the very first sentence, I've already implemented shadow map shadows with some filtering to soften them, I'm just using tex2D function to do the shadow map lookup (as it is in the Shadowmap example in DX SDK).

This is actually quite weird, on one hand I'm still finding notes about something like HW soft map shadows which work only on nVidia cards (including gamedev.net forums, that's btw where I first found it) with "built-in" PCF enabled just by using bilinear sampling, while on the other hand there seems to be nobody really using it :)
Looks more and more like a myth to me :D

Share this post


Link to post
Share on other sites
The first article I found mentions nothing of this automatic tex2Dproj shit:
http://www.riemers.net/eng/Tutorials/DirectX/Csharp/Series3/Shadow_mapping.php

However, also on the very first page of results for "shadow mapping HLSL", was what you are looking for: On nvidia hardware, create the depth map with D24S8_SHADOWMAP: http://developer.nvidia.com/forums/index.php?=&showtopic=34
I've never used that format before, and it sounds like it still doesn't do what you want (automatic depth comparison), just that it does the filtered sampling for you.

The Gpu gems chapter 10 is not using shadow maps as you think. Those textures are simply textures they project into the scene to look like shadows. There is no shadow mapping involved. In chapter 11, they do the sampling I mentioned if you want soft shadows and don't use the D24S8_SHADOWMAP format. But they are doing the sampling AFTER they have compared the shadow map with the scene and produced a shadow texture.

Share this post


Link to post
Share on other sites
Tom KQT is right, the depth comparison and filtering ARE done automatically if you use hardware shadow mapping..and yes tex2DProj is the way to do it. (it only works on Nvidia GPUS unfortunately..I dont know how ATI does it)

Get the Nvidia GPU programming guide (its downloadable and packed with lots of useful info) and see page 52..this explains it in detail..the basic thing is this:

In DirectX, you can create a hardware shadow map in the following way:
1) Create a texture with usage D3DUSAGE_DEPTHSTENCIL
2) The format should be D3DFMT_D16, D3DFMT_D24X8

then you just make your texture projection matrix like this
V’ = Bias(0.5/TexWidth, 0.5/TexHeight,
Bias(0.5, 0.5, 0) *
Scale(0.5,0.5,1) *
ViewProjsaved * World * Object * V

then...

11) If using pixel shaders 1.4 or higher, perform a projected texture fetch from the shadow map sampler.

12) The hardware will use the shadow map texture coordinate’s projected x and y coordinates to look up into the texture.
13) It will compare the shadow map’s depth value to the texture coordinate’s projected z value. If the texture coordinate depth is greater than the shadow map depth, the result returned for the fetch will be 0 (in shadow); otherwise, the result will be 1.
14) If you turn on D3DFILTER_LINEAR for the shadow map sampler, the hardware will perform 4 depth comparisons, and bilinearly filter the results for the same cost as one sample—this just makes things look better.

Share this post


Link to post
Share on other sites
I've never seen that behavior, and the link earlier to a post by an admin on nvidia's site contradicts what you said (you need to use D24S8_SHADOWMAP to get PCF filtering, unless you meant straight up bilinear filtering, which doesn't smooth the results much...)

I suppose this could have been happening to me all along and I never would have noticed because a depth comparison would still result in the right answer, but it would obviously be unnecessary. Sorry Tom, this is quite a suprise to me after using this for several years now... Luckily I never wanted the actual depth value, I would have been seriously pissed if this would happen automatically and I couldn't stop it without copying the depth map to a non-depth stencil texture.

To answer your original question, to get hardware PCF, use D24S8_SHADOWMAP.

Share this post


Link to post
Share on other sites
Thx God, I was slowly starting to feel like an idiot :) as those GPU Gems articles really smells of real shadow mapping, there are few sentences which point to that, for example a mention that you cannot simply blur the shadow map (which would be possible with no problem for projected shadows).

About the format D24S8_SHADOWMAP, I found something about it too, but DirectX doesn't know this format :O
It really seems to me that what Matt Aufderheide said should work (formats without _SHADOWMAP), I'll give it a try. Currently I'm creating the shadow map differently, I'm writing the depth in a pixel shader to a D3DFMT_R32F texture (as in DX SDK sample), not simply employing a depth stencil. That can be why GC doesn't know I would like to make shadows and not just projection.

Thx everybody so far. I'll let you know when I test it.

Tom

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this