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

Recommended Posts

So after getting some help from this forum  , I was able to get omni-directional hard shadows to work with shadow mapping.  I'm now trying to take it step further and get soft shadows.  I've implemented a version of PCF found here :http://http.developer.nvidia.com/GPUGems/gpugems_ch12.html

http://imgur.com/URjSiOS

As you can see, the shadows are still a little jaggy. It can't really be seen in the picture but there is also some pretty noticeable aliasing when moving.  The problem becomes more pronounced as you move further away from the light as the shadow is restricted to fewer pixels on the shadow map.

I've thought of implementing ESM and blurring the result, but I think that might be too slow for run-time as I would need to blur the 6 faces of the cube map and so it wouldn't really scale well. I was going to attempt and test this anyway, but I've found that I'm unable to properly bind the texture description to support D3D11_BIND_UNORDERED_ACCESS.

I think since the main issue stems from perspective aliasing, Cascaded Shadow Maps would probably be the best solution. I've mostly seen cascaded shadow maps used for directional lights, are they also applicable for omni-directional lights? (I'd imagine that it would double/triple the number of cubemaps that I need for each pointlight)

So I guess my question boils down to: should I implement Cascaded Shadow Maps for omni-directional lights or is there a better way?

Share on other sites

Also when rendering into the shadowmap for each face, what is your proj matrix zNear and do you use the lights max radius as zFar?

The aliasing when moving is called shimmering. Should be some good google hits. Higher resolution and tighter bounds helps but you can never fully negate the problem. I believe if you can make the camera move only in shadowmap pixel-sized increments it will help too,

I've never had any aliasing issues to warrant a CSM for point lights. Whats the radius of your point light?

Edited by KaiserJohan

Share on other sites

Currently, the resolution is 2048x2048.

Also when rendering into the shadowmap for each face, what is your proj matrix zNear and do you use the lights max radius as zFar?

My zNear is 0.1f and currently, my zFar is just a constant 40.0f. I'm currently only using a simple attenuation formula:

c1,c2,c3 are user defined constants

d is the distance  between the pixel's distance from the light.

Attenuation = 1 / (c1 + c2 * d + c3 * d * d)


Unfortunately, I'm not sure how to bound this equation to find the max radius of my point light. I think this equation worked okay for Forward Rendering, but it doesn't appear to work too well for Deferred.  Do you know of any better attenuation formulas?

Share on other sites

So I guess my question boils down to: should I implement Cascaded Shadow Maps for omni-directional lights or is there a better way?

Cascaded shadow maps are for directional lights and are not specific to your problem, which is basically poor filtering.
I am assuming you followed the article and are using 4 taps. The more taps, with appropriate spacing between them, the better the quality, but the more expensive the shadows. You either have too few taps or poor spacing between them, or both.

Currently, the resolution is 2048x2048.

That’s ridiculous for anything but a cinematic. Or just testing.

I think this equation worked okay

This equation was never okay. It was garbage even in the days of the fixed-function pipeline.

for Forward Rendering

Forward rendering and deferred rendering are irrelevant—you get the same amount of light either way. If you don’t, you have an error in one implementation or the other.

Do you know of any better attenuation formulas?

Given the distance of the pixel from the light and the light’s radius (range):
float Sqr( float _fVal ) { return _fVal * _fVal; }
float Falloff( in float _fDistance, in float _fLightRadius ) {
float fFalloff = 0.0;
fFalloff = Sqr( saturate( 1.0 - fDistOverRadius4 ) );
fFalloff /= Sqr( _fDistance ) + 1.0;
return fFalloff;
}
float Falloff( in float _fDistance, in float _fLightRadius ) {
float fFalloff = max( 1.0 / Sqr( _fDistance ) - 1.0 / Sqr( _fLightRadius ), 0.0 );
return fFalloff;
}

L. Spiro Edited by L. Spiro

Share on other sites

Given the distance of the pixel from the light and the light’s radius (range):
float Sqr( float _fVal ) { return _fVal * _fVal; }
float Falloff( in float _fDistance, in float _fLightRadius ) {
float fFalloff = 0.0;
fFalloff = Sqr( saturate( 1.0 - fDistOverRadius4 ) );
fFalloff /= Sqr( _fDistance ) + 1.0;
return fFalloff;
}
float Falloff( in float _fDistance, in float _fLightRadius ) {
float fFalloff = max( 1.0 / Sqr( _fDistance ) - 1.0 / Sqr( _fLightRadius ), 0.0 );
return fFalloff;
}

Thanks for the suggestions and clarification.  I changed my attenuation and bounded zFar to the light range and that has helped.

That’s ridiculous for anything but a cinematic. Or just testing.

I tried reducing the map size to 512x512 for each face, but this really diminishes the quality of the shadows.

(On the plus side, my shadows are significantly cheaper because of this.  )

http://imgur.com/a/0Ok7O

Is this how shadows should look at 512x512 per face?  In the picture, the characters are about 5-6 units away from the light and the light has a radius of 20. And zNear is 1.0f.

I am assuming you followed the article and are using 4 taps. The more taps, with appropriate spacing between them, the better the quality, but the more expensive the shadows. You either have too few taps or poor spacing between them, or both.

I am using 4 taps, but I'm still playing around with the filter to get better results.

Share on other sites

Is this how shadows should look at 512x512 per face?

For the number of taps you make, yes.

I am using 4 taps, but I'm still playing around with the filter to get better results.

When it comes to filtering a cube texture in this manner taps are your filter. Aside from taking advantage of hardware-accelerated PCF via shadow texture fetches, the rest is just the number of taps and their locations.

Increase the number of taps and use Poisson distribution to decide where to tap.

L. Spiro

Share on other sites

Penumbra size = Light size * (Blocker distance  / Total distance)

Light size is known constant. Total distance is given. For blocker distance you need to make blocker search. Usually you need bit few samples there than in shadow filtering pass. I just discard all samples that are further than total distance and average rest of the distances. If there are no blockers you can just skip the filtering pass.

Share on other sites

Penumbra size = Light size * (Blocker distance  / Total distance)

Light size is known constant. Total distance is given. For blocker distance you need to make blocker search. Usually you need bit few samples there than in shadow filtering pass. I just discard all samples that are further than total distance and average rest of the distances. If there are no blockers you can just skip the filtering pass.

Are you referring to PCSS?  If so, how is that applied to a pointlight?