Cascaded Shadow Map Parameter Combinations and Permutations

Started by
3 comments, last by SBD 8 months, 2 weeks ago

I've been refining and expanding my cascaded shadow mapping (as a by-product of chasing LOD transition issues as detailed in this topic: https://www.gamedev.net/forums/topic/714679-lod-transition-shadow-artifacts/5458092/). I've implemented and have several variations and additions working to various degrees (back-face shadow generation, normal offset bias, etc.), and it's raised some practical questions about what parameters/techniques are most useful, and in what combination. I'm curious to hear your own experiences, specifically as it relates to the following:

1) When using face normal offset on the shadow-receiving geometry (scaled by its angle to the shadow-casting light), which seems to do a pretty great job of minimizing shadow acne, do you still utilize depth bias and/or slope-scaled depth bias during shadow generation? Most examples I've seen don't, and it seems the face normal offset is performing a similar function to slope-scaled depth bias, just on the receiving geometry (and thus at a more precise granularity). I continue to do a per-cascade depth bias applied manually on shadow-receiving geometry, but slope-scaled depth bias on generation is an open question. Perhaps there's value in keeping it that I'm overlooking? Obviously, one is based on the slope of the receiving geometry, and the other is based on the slope of the shadow-generating geometry, so I'm scrunching my face thinking of how that combo might interact and provide value.

2) Also regarding face normal offset, is there any value in specifying per-cascade values for the normal offset scaling factor? That obviously greatly depends on what units you are basing things off of. If one is automatically scaling things based on shadow texel size, then a single scaling factor seems sufficient. It's also common to automatically apply a cascade scaling factor to it. However, maybe there's additional benefit for tweaking this per cascade? What's your experience?

3) When doing back-face shadow generation, biases are essentially weighted/constructed to favor being in shadow versus being un-shadowed. It also seems to me that the assumption that your shadow-generating geometry is "back face watertight" also implies a thickness that might just make a raw depth bias more-or-less unnecessary (ignoring double-sided geometry as an exception). What's your experience in switching from front-face to back-face shadow generation, as it relates to bias values?

Advertisement

I've managed to get consistent results across various permutations/combinations of face normal offset and front/back face shadow generation, and thought I'd report my findings.

1) When using face normal offset on the receiving geometry, there seems to be no harm in combining that with slope scaled bias when generating the shadow maps. I'm still not real clear on the potential interaction between the two, but I've essentially just left my slope scaled depth bias alone (same value as when I'm not using face normal offset). Obviously, plain depth bias is still necessary in either case.

2) A single face normal offset scaling factor seems to suffice across all shadow cascades. The big caveat here is that I'm also applying the shadow cascade scale to this calculated magnitude. Regardless, it seems a separate, tweakable scaling factor per-cascade is unnecessary.

3) For back-face shadow generation, fewer things need to be inverted than I suspected. Regarding face normal offset calculations, those remain the same; I had thought I might want to invert the offset direction, or potentially reverse the magnitude to the shadowed side, but none of those presumptions were correct. The only tweak I made to any bias for back-face generation was to set my plain per-cascade depth bias to zero. Per my above speculation, geometric (model) thickness is essentially making plain depth bias unnecessary. I did experiment with negating the plain depth bias, as it still seems that we would want to weight towards shadow-generating surfaces being in shadow, but I got over-shadowing in further cascades. So it seems if one can make some reasonable guarantees about shadow-generating geometry thickness, then bias is unnecessary. I've also left the slope scaled depth bias on shadow generation alone (same value as front-facing). I have a sneaking suspicion that not inverting this might be the cause of the plain depth bias inversion not producing expected results, but since things seem to be working ok as-is, I have left it alone.

One further observation is that it seems useful and even necessary to apply depth bias on the receiving geometry in the shader, rather than relying on rasterizer depth bias when generating the shadow maps. Specifically, one often needs to tweak biases on a per-render-item basis; in my case, I need different biases for double-sided geometry versus front/back-face culled geometry when shadowing them.

SBD said:
One further observation is that it seems useful and even necessary to apply depth bias on the receiving geometry in the shader, rather than relying on rasterizer depth bias when generating the shadow maps. Specifically, one often needs to tweak biases on a per-render-item basis;

That's interesting. I have only used slope scaled bias on shadow map generation and have trouble completely removing acne, maybe I will try bias on the receiving end.

Aressera said: That's interesting. I have only used slope scaled bias on shadow map generation and have trouble completely removing acne, maybe I will try bias on the receiving end.

In my case I needed to make a decision on how to handle double-faced geometry for applying back-face-generated shadow maps. I decided to bias those to be out of shadow (as when doing front-face shadow generation), meaning they needed a different bias than normal culled geometry. But one could easily decide to bias them to be in shadow, in which case the single (well, per-cascade) bias value would suffice…it just came down to what I preferred.

Regarding shadow acne, the face normal offset did a pretty good job of eliminating that. MJP's article and source do a good job of explaining it (check out the Biases section): https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/

If you're looking at the source for that, be aware that he generates the cascade offsets and scales and applies them slightly differently than I've seen elsewhere. It's all correct, but I got briefly tripped up thinking the scale/offset transformation of the pixel into shadow view space was reversed (he explained why it wasn't in a reply to my GitHub comment).

This topic is closed to new replies.

Advertisement