This is just the beginning of “really easy shadows”. I enjoy how simple API we have (just a checkbox really!) and how great it is to play with shadows in the editor. But we can improve the functionality underneath now 🙂
The most important TODO here is that we plan to expose shadow maps in the same way. Actually shadow maps should be in the future the default algorithm activated by Shadows (and toggling between shadow maps and shadow volumes should be done using an independent property like ShadowMode = smShadowMaps, smShadowVolumes).
Shadow maps have a number of advantages — they do not require the shadow caster to be 2-manifold, they already work on both desktop and mobile (OpenGLES), they can be applied on multiple light sources independently with correct result.
While we had shadow maps implemented for years, with some impressive demos (see features section) but they do not work (yet!) across scenes, which means that the light that casts shadow must be in the same glTF/X3D file as the shadow receiver. This makes them not suitable to use shadow maps on our light nodes.
The plan is to, well, remove this limitation (#284). Shadow maps should work cross-scene, they should not transform the X3D graph (whole work done by CastleInternalShadowMaps should be removed) and the renderer should just take and use at rendering a shadow map information attached to any light (and the renderer should add using that shadow map to particular shape).
Shadow volumes for now carry a few limitations:
The unfixable limitation is that shadow caster has to be 2-manifold, i.e. every edge must have exactly 2 neighboring faces, so the whole shape is a closed volume. Both CGE and 3D authoring tools like Blender help you modeling such shapes — see Make 3D models of shadow casters geometry to be 2-manifold.
The current limitation of shadow volumes in CGE is that we allow them from only one light (so set Shadows to trueonly on a single light!)
We could improve that, though note that it will increase the number of rendering passes, in general you need to do 2^shadow_volumes_lights passes. So this technique is really not feasible for multiple lights. (Shadow maps scale much better.)
Most things we announce are available immediately, unless I specifically write they are only on some branch/PR. Just head over to our downloads on Download | Castle Game Engine , they point now to “7.0-alpha.snapshot” version (already newer than “7.0-alpha.2”). This “snapshot” version is automatically updated whenever the “master” branch changes, after it passes a lot of automatic tests (it takes ~6h to make sure it compiles and all tests pass everywhere).
It already contains working shadows, including the examples/viewport_and_scenes/shadows .
I see this method effects self-shadowing, as well. Lovely!
If you can increase this to 2 lights, it would allow for more impactful effects, because your user could use one for, say, the sun, and the second reserved for special effects like explosions or car headlights. You definitely want things like explosions and headlights to cast shadows because they look very weird without it.
If you could make this a dynamic thing per object, such as determined by the most intense lightsource nearby, or to multiply the amount of shadows per object based on relevant lightsources, it would make it possible for scenes like large medieval war-camps with lamps and firepits to have rich cast-shadow effects all around that move appropriately with the characters.
But this is an exciting start! Keep up the awesome work, CGE is becoming more impressive with everything you do!
On top of my priority is now to also enable “shadow maps” in the same way (i.e. the trivial checkbox Shadows should turn them on, and some additional property like ShadowMode should control the algorithm - shadow volumes or shadow maps).
We have shadow maps working already: Shadow Maps | Castle Game Engine but they do not yet work “across scenes” (they only work if the light source is part of the same X3D/glTF file) due to limitation of my current implementation, so I cannot expose them as trivially on light sources by “just a checkbox”. I shall remove this limitation
Shadow maps would also enable to make the decision “which light sources cast shadows” dynamic, as you propose. This feature is not (easily) possible with shadow volumes, where the whole world needs to be rendered with all lights’ combinations (and then we just mask the appropriate parts using stencil buffer). With shadow maps, such decision would be possible, as each shadow receiver in shadow maps is calculated independently.
Shadow maps would also allow even better self-shadowing In case of shadow volumes, the self-shadowing may sometimes show small artifacts (due to the fact that shadows are determined by silhouette of the shadow caster, which is derived from the mesh edges), like on the screenshot below.
With shadow maps, you get a “bias” parameter to control this. With shadow volumes, there’s no way to add such bias without a performance cost (because if you shift the shadow quads, you will have to render additional geometry to make sure the shape is “closed”).
And finally, you can use both shadow volumes and shadow maps in one world. That is, you will be able to e.g. have one bright light (like sun) cast hard shadows using shadow volumes, and the rest lights cast shadows using shadow maps.
Extending shadow volumes to enable multiple lights is still useful of course.
Shadow volumes e.g. are precise and have hard edges – which may be an advantage over shadow maps in some settings. E.g. shadow volumes are better to cast hard shadows like by a bright sun in the middle of sunny day.
I tried the shadow with my characters (GLTF). It doesn’t work. The characters are in a correct shape (2-manifold), but I used more then one material in blender to set the colors.
After rebuilding to one material with image and uv-editing it works.
Is this behaviour correct? Is the limit only one material?
This is a consequence of limit " each shape must be 2-manifold" mentioned on Shadow Volumes | Castle Game Engine . In glTF it means “each glTF primitive must be 2-manifold” (glTF primitive corresponds to X3D shape). When exporting, Blender splits your object (with multiple materials) into multiple glTF primitives.
So, it would be more precise to say there “each glTF primitive (which is a subset of Blender mesh, limited to a single material)” must be 2-manifold.
It is possible to counter this limitation in the future. We could consider, for shadow volumes, larger units – and then only such “larger unit” (like whole Blender object) would need to be 2-manifold.