- Umbra can be used to perform volumetric queries to cull local lights
- Shadow-casting lights can be clipped to occluding geometry
There are a few key differences between culling lights and culling regular objects. Solid objects can be culled if no part of their surface is visible. In contrast, lights are volumetric and do not have a surface like solid objects. Thus, the visibility of a light needs to be determined not by the visibility of its “surface”, but rather by the visibility of its volume. Furthermore, a shadow-casting light can be occluded by a surface even though a part of its volume may overlap an area visible to the camera. Thus, the light can be “clipped” to the occluding geometry.
Consider the following example, illustrated in the below figure. There are two rooms, A and B, adjacent to each other but separated by a solid, occluding wall. The camera is located in Room A, looking at Room B. There is a point light, whose origin (seed point) is inside Room B, but whose volume extends beyond the occluding wall, to Room A. In this situation, the light can be culled even though a simple volumetric test would deem it visible, because the solid occluding wall prevents the light from having any impact on Room A’s lighting. As the Umbra occlusion data contains a topological representation of the geometry, leveraging this kind of connectivity information is very easy, enabling very accurate local light culling.
The point light may be culled from Room A, even though its volume extends through the solid wall
In Umbra 3.2, local light culling is introduced by adding Query::queryLocalLights(). As its input, it simply takes a list of spheres to be tested for visibility (lightCenters, lightRadii, lightCount), in addition to the list of clusters visible to the camera (visibleClusters).
Thus, the typical workflow is to issue the camera visibility query first to obtain the list of visible clusters. This is done by specifying a Visibility object containing a reference to a cluster list (Visibility::setOutputClusters()) when calling Query::queryPortalVisibility(), and then using the returned cluster list (Visibility::getOutputClusters()) when issuing the subsequent local light query.