/Tiny-OpenGL-Shadow-Mapping-Examples

Compact OpenGL Shadow Mapping Examples in a single compilation unit

Primary LanguageCMIT LicenseMIT

Tiny-OpenGL-Shadow-Mapping-Examples

Compact OpenGL Shadow Mapping Examples in a single compilation unit.

Features

  • A single .c file per example.
  • No extern math library used. No math structs used. Just plain float arrays.
  • Helper functions (mainly math stuff) grouped in the header helper_functions.h, for easier inclusion into user code.
  • Only a single directional light is used in all the examples.
  • Currently all the examples are flicker-free while the camera moves and rotates (on static objects). Please see the implementation section below for further info.

Dependencies

  • glut (or freeglut)
  • glew (Windows only)

How to compile

Compilation instructions are at the top of each .c file. All the demos have been tested on Linux using an NVIDIA graphic card (AMD/ATI might need some glsl tweaking).

Help needed

The demos: shadow_mapping_sESM1.c, variance_shadow_mapping.c, variance_shadow_mapping_EVSM2.c and variance_shadow_mapping_EVSM4.c are all WRONG! The shadows should look blurry and instead are sharp! If you can help to fix these (and other) issues, please post a message in the "Issues" or "Pull requests" sections. Thank you in advance!

Screenshots

shadow_mapping.c shadow_mapping_advanced.c shadow_mapping_cascade.c shadow_mapping_cascade_advanced.c shadow_mapping_cascade_texture_array.c shadow_mapping_cascade_horizontal_and_vertical.c shadow_mapping_pcf.c variance_shadow_mapping.c variance_shadow_mapping_MSM4.c

Implmentation

All the examples in this repository implement "Stable Shadow Mapping". That means that static shadows should not flicker when the camera moves or rotates, at the expense of the shadow resolution, that is usually only a half of the resolution that can be used in any "Non-Stable Shadow Mapping" technique.

In addition, the light matrices calculated by the "Stable Shadow Mapping" algorithm are not optimal for frustum culling usage, and if we want to filter the shadow map (like in VSM), we waste a lot of resources, unless we manage to calculate a tighter texture viewport somehow (we address this issue in shadow_mapping_advanced.c and shadow_mapping_cascade_advanced.c).

The demos shadow_mapping.c,shadow_mapping_cascade.c and shadow_mapping_cascade_texture_array.c can be compiled with the optional definition USE_UNSTABLE_SHADOW_MAPPING_TECHNIQUE so that we can compare the two techniques.

The "Stable Shadow Mapping" algorithm calculates the minimum sphere that encloses the camera frustum, and further encloses it in a light ortho projection matrix.

Calculation of the camera frustum center and radius

The picture below is valid for every frustum field of view (fovx, fovy and fovd), but if we use the diagonal fov, then the points at tn and tf are real frustum corners. (n is the near camera frustum clipping plane and f is the far camera frustum clipping plane)

frustum_radius

θ = (fovd/2);   // half diagonal fov
t = tan(θ);
tSquared = (1.0+ar*ar)*tan(0.5*fovy)*tan(0.5*fovy); // ar = camera aspect ratio
h = 0.5*(f+n) ;  // half way between near and far plane
d = h*(1.0+tSquared);   // Found after all the math passages from the picture above
if (d>f) d=f;           // Clamping to save some shadow resolution
r = sqrt((tSquared*f*f) + (f-d)*(f-d));

Useful Links

opengl-cascaded-shadow-maps with code at the bottom

graphics-tech-shadow-maps-part-1 (explains why shadow resolution gets wasted)

graphics-tech-shadow-maps-part-2 (proposes a method to save GPU memory)

A sampling of shadow techniques

GPU Gems 3 - Chapter 10. Parallel-Split Shadow Maps on Programmable GPUs

variance_shadow_mapping.c is greatly based on this Fabien Sanglard's work

glsl-fast-gaussian-blur: my blur filters are based on this Github repository

Github repository containing Direct3D implementations of many modern shadow mapping techniques