15
$\begingroup$

I'm fiddling with simple procedural 3D modeling to make teeny buildings for 3D printing. An Example:

The Building


To make the models more readable onscreen, I've implemented basic shadow mapping for a single directional light. Since my scene isn't changing, I just render the shadow map once using an axis aligned box of the scene to figure out what the bounds of the shadow map should be. The shadows and bounds look like I've got all the matrices right, but coming in a bit closer looks terrible:

Closeup of Tower

From the reading I've done, I understand the peter panning and what I might do about it, but the ragged edges, which I believe is a form of projective aliasing, look so bad that I think something is wrong in my basic implementation.

I hacked the pixel shader to show the shadow texel boundaries:

Showing Texel Boundaries

I've got bilinear filtering on in the texture (without it, I get serious shadow acne). Sadly, my attempt at PCF failed too - it looks just as ragged:

enter image description here

Here's the single sample case with bilinear filtering disabled:

enter image description here

Does this look like "typical" projective aliasing? Could dynamic rendering of the shadow map, using the view frustum clipped to the scene, possibly with cascading, address the issue?

Edit: Adding a closeup of bilinear filtering, post shadow comparison, just to show what I get. Bad shadow acne shows up because of interior edges; I'm modeling with stacked virtual blocks and not doing a proper union operation. From my reading, implementing boolean operations on polyhedra is not trivial, but will also allow me to implement static shadow volumes as well as clean up for some 3D printing software.

Bilinear Filtering

$\endgroup$
10
$\begingroup$

Shadow mapping with acceptable quality is quite a journey. So you implemented first step - basic shadow map that encompass whole scene statically. This means that shadow map texel size in light view space to texel size of rendered scene in camera view space ratio is quite big, resulting in aliasing. To reduce this ratio closer to 1:1 there are techniques you mentioned like:

  • the easiest way is increasing size of your shadow map, to find the value with still optimal performance,
  • align shadow map with camera view frustum. Then shadow map encompass smaller part of the scene, so it reduces aliasing,
  • this can be improved to CSM, which does the same but you need to render scene for each of cascade with different center position of light view matrix based on center point of each slice of frustum.

Some of the basic techniques of smoothing the edge of shadow:

  • obviously PCF, but is it recommended to combine your PCF implementiation with built in hardware PCF (in Opengl - using sampler2DShadow). This would result in less loop iterations from your side and cheaper PCF,
  • blockiness of edges can be exchanged for noise using rotated Poisson Disk. Samples used to sample from shadow map are rotated randomly with each iteration of PCF loop.

You can also research the edge smoothing techniques like:

  • rendering shadow map to MSAA applied framebuffer,
  • further enhancing PCF by interpolation,
  • increasing number of samples with temporal blend.

PCF basic technique suffers from shadow acne which can be fixed by applying some offset in shadow test. Calculating the size of this offset is also area of research.

Other more advanced shadow map methods include:

  • Exponential Shadow Maps and Variance Shadow Maps - in most cases do not suffer from shadow acne and offer smooth edges without blockiness, but in cost of some light leaking situations,
  • Exponential Variance Shadow Maps - probably most advanced technique of 2D depth map shadow mapping, combines great smoothness of VSM and resolves light leaks, in a cost of memory usage doubling,
  • Percentage Closer Soft Shadows - basic technique of enhancing traditional shadow maps with varying penumbra size,
  • Multiview Shadow Maps - multiple shadow maps of some technique, arranged on area light, for computing realistic soft shadows with varying penumbra size,
  • Deep Shadow Maps - for enhancing volumetric scattering with shadows,
  • Real time ray traced shadows - probably the future.

You didn't fail with PCF, it looks like that:)

I wish there was a way to apply gaussian blur on shadow map in camera view space, but it doesn't work as expected.

$\endgroup$
  • $\begingroup$ Part of this comment is thanking you for your answer, so I just thought I'd let you know since you won't get a notification from there. $\endgroup$ – trichoplax Dec 20 '16 at 20:51
  • $\begingroup$ Yes, I saw it but thanks. $\endgroup$ – narthex Dec 20 '16 at 21:19
1
$\begingroup$

You've said that "... bilinear filtering on in the texture ...". It seems that you are interpolating the depth values of the shadow map. The correct way of using interpolation with the shadow map is to apply it over the outcomes of the shadow tests (as far as I remember, OpenGL supports that). You might even combine the interpolation of the outcomes of the shadow tests with PCF, which will deliver much better results. However, as you might have noticed, aliasing is a plague that always pursue the shadow mapping :)

Although I understand that you are looking for solutions regarding shadow mapping (even because it is quite simple to implement), have you ever considered the use of shadow volumes? It is much more intricate to implement, but does not suffer from aliasing at all, and I think would fit nicely your purposes.

$\endgroup$
  • $\begingroup$ Thanks very much for the answers! To get the results I'm looking for, it might be appropriate to switch to shadow volumes. The codeflow link provided under "interpolation" is very useful - thanks! $\endgroup$ – Daniel M Gessel Dec 17 '16 at 13:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.