Table of Contents
- 8.1. Quick overview how to use shadow volumes in our engine
- 8.2. Inspecting models manifold edges
- 8.3. Ghost shadows
- 8.4. Problems with BorderEdges (models not 2-manifold)
You can easily render shadow volume for any
Some features (see any article about shadow volumes to know what they mean) :
Silhouette edge detection is done, of course the model must be 2-manifold for this to work.
ManifoldEdges structure is prepared once during pre-processing step (by
prShadowVolume, or simply on first call to
RenderShadowVolume). This allows rendering shadow quads with silhouette detection in O(n+m) time, where n is a number of edges and m is a number of triangles (these are roughly equal since on a perfect 2-manifold 3 * m = 2 * n). Without calculated ManifoldEdges, this would have to take square time, O(m2).
To account also models that are not completely 2-manifold, we have BorderEdges list with edges that have only one neighbor triangle. Actually, it lists edges with any odd number of neighbors (each neighbor pair makes one edge in ManifoldEdges, and then one left neighbor makes one BorderEdges item). All BorderEdges are always considered part of the silhouette. This is not a perfect solution, further in this chapter I present when this fails. When it fails, there are two solutions:
fix the model to be 2-manifold.
or use the much slower algorithm version that doesn't do silhouette edge detection.
Both Z-pass and Z-fail approaches are done. We automatically detect when Z-fail is needed, and in 99% of the cases we can use faster Z-pass approach.
Both positional and directional lights are supported.
Using homogeneous coordinates tricks: we render shadow quads vertexes in real infinity, and we can use perspective projection that has no far clipping plane.
We do shadow volume culling for scenes (that is, we try to avoid rendering shadow quads when it's obvious the scene shadow can't be visible within current camera frustum). Implemented in
TGLShadowVolumeRenderer.InitScene. It's not fully implemented, we could take more conservative convex hull between light position and frustum. But it seems that this wouldn't improve culling significantly, current approach gives us almost as much as we can get from frustum culling.
More drastic improvements can only come from the use of portals.
TCastleSceneManager does pretty much
everything for you. Just set
That's it — we will take care to render with shadow volumes.
You can change
ShadowVolumesdynamically during the game (for example, if user changes video preferences).
ShadowVolumesPossibleshould remain constant and reflect whether we have stencil buffer available. Dynamically changing
ShadowVolumesPossibleis actually allowed, but it may cause costly recalculation once the models are actually loaded. Also, projection may need to be reapplied (only when
ShadowVolumesPossible, we force infinite far plane, which is needed for z-fail, when camera near plane is inside the shadow volume).
You should also take care to initialize OpenGL context requiring
stencil buffer (8-bit should be enough for practical uses).
This is something that has to be requested outside of scene manager.
The simplest way to do this is to use
method instead of
To actually define what lights are used for shadow volumes,
to true on some VRML/X3D light node. See https://castle-engine.io/x3d_extensions.php#section_ext_shadows
for details. Alternatively, you can control the main light source
If you define your own
be sure to override
See API reference for details now to handle it.
You can change
CastShadowVolumes properties of every
The whole approach is quite flexible and is used throughout my whole engine, and it will use all implemented shadow volume optimizations under the hood. For example, see "The Castle" game, where almost everything may have a shadow rendered by shadow volumes — creatures, level scene, level objects. And everything goes through this same approach, getting all optimizations.