On 9/11/2017 at 4:38 AM, matt77hias said:
I wonder, however, how many shadow maps are typically used? One omni-light already results in the generation of six shadow maps, each resulting from a separate depth pass, which seems huge, even in the presence of some CPU-side culling (for this reason, I don't want to use the GS)? If you are not be carefull with the fall-of distance, the depth passes of a single omni-light can become a bottleneck?
Does one normally support multiple formats (16bit vs. 32bit) and multiple resolutions?
Because, as mentioned, scenes can vary widely, the common way to decide how many shadows you will have is derived from a performance goal on a specific target spec. In other words, determine how many shadows you can have while maintaining X FPS on Y hardware.
The reason you should be using an algorithm like this to determine your own metrics is because not only do different scenes in different games come with different performance compromises, your own implementation of shadows may perform very differently from others'. Your question is useful for allowing you to consider how optimized shadow maps must be in other games and for you to consider how much you have to do to get there, but if you were asked right now by a boss to estimate how many shadows you can use you would use the above-mentioned process.
To give you actual stats and an idea of the optimizations used, here is what I did on Final Fantasy XV.
We had a basic implementation likely matching what you have, with cube textures for point lights and different textures for the rest (4 textures for a cascaded directional light and X spot lights). The first thing I did was improve the culling on the cascaded directional light so that the same objects from the nearest cascade were not being needlessly drawn into the farther cascades. If you aren't doing this, it can lead to huge savings as you can avoid having your main detailed characters being redrawn, complete with re-skinning etc.
Next I moved the 6 faces of a cube texture to a single 1X-by-6X texture. So a 512-by-512 cube texture became a single 512-by-3,072 texture. Although you must write your own look-up function that takes 3D coordinates and translates them to a 2D coordinate on this texture, it comes with a few advantages in caching, filtering, clearing, filling, and most importantly it prepares for the next big optimization: a shadow atlas.
Now that all shadows were being drawn to 2D textures, I created a texture atlas for all the shadows except the cascaded ones. A single large texture for all the point and spot lights. It was 2,048-by-2,048 first but could grow to 4,096-by-2,048 if necessary. Putting all the point and spot shadows into a single texture was a huge gain for many reasons, but one of main gains was that we had access to all the shadows during a single lighting pass, which meant we could draw all the shadows in a single pass instead of many.
At this point our limit was simply how many shadows could be drawn until the texture atlas got filled, sorted by priority largely based on distance. As mentioned by MJP, an important aspect of this is to cull all six faces of a point-light shadow. Any shadow frustums not in view meant less time creating shadow maps and more room for other shadows in the atlas.
Next, I wanted the shadow maps to have LOD, as the smaller shadow sizes would allow faster creation, and smaller shadow maps meant more shadows could fit into the atlas.
Each shadow frustum (up to 6 for point lights and 1 for each spot light, where each shadow frustum at least partially intersects the camera frustum—any shadow frustums fully outside the view frustum would be discarded prior to this step) was projected onto a small in-memory representation of a screen and clipped by the virtual screen edges.
This sounds complicated but it is really simple. The camera's world-view matrix translates points into a [-1,-1]...[1,1] space on your screen, so we simply used that same matrix to transform the shadow frustum points, then clipped anything beyond -1 and 1 in both directions.
Now with the outline of the clipped shadow frustum in -1...1 space, taking the area of the created shape gives you double the percentage of the screen it covers (represented as 0=0% to 2=100%).
In short, we measured how much each shadow frustum is in view of the camera. Based on this percentage, I would drop the shadow resolution by half, or half again if even less was in view, etc. I believe I put a limit at 64-by-64.
If you play Final Fantasy XV, you can see this in action if you know where to look. If you slowly move so that a shadow from a point light takes less and less screen space you might be able to see the resolution drop.
Now with the shadow-map LOD system, most shadows are drawn at a lower resolution, only going full-size when you get near and are looking directly at the shadowed area. Because this actually affects so many shadows, the savings are significant. If you decide to keep the same limit on shadows as you had before you will find a huge gain in performance. In our case, we continued allowing the shadow atlas to be filled, so we were able to support double or more shadows with the same performance.
Another important optimization is to render static objects to offline shadow maps. A tool generates the shadow maps offline, rendering only static objects (buildings, lamp posts, etc.) into them. At run-time, you create the final shadow map by copying the static shadow map over it and then rendering your dynamic objects (characters, foliage, etc.) into it.
This is a major performance improvement again. We already had this for Final Fantasy XV, but since I added the shadow LOD system I had to make the offline static shadows carry mipmaps. It is important to note that the shadow mipmaps are not a downsampling of mip level 0—you have to re-render the scene into each mipmap, again with some lower limit such as 64-by-64.
All of this together allowed us probably around 30 shadow maps with the ability to dynamically scale with the scene and without too many restrictions on the artists. Shadow maps were sorted by a priority system so that by the time the shadow atlas was filled, the shadows that had to be culled were distant, off-to-the-side, or otherwise unimportant.
L. Spiro