Hierarchical Occlusion Culling
Another buffer is then rendered out known as the Depth Estimation Buffer (DEB). On the occluder, the furthest point from the viewer is found and its depth is stored. From there, a screen-space AABB is made around the occluder and the AABB is rendered to the DEB with the float value of the furthest depth.
The next step is to render the objects. First, provided the occluders are actual objects, render them only using frustum culling. Next, when rendering all the other non-occluders we start with frustum culling, then we move to check occlusion. By creating a screen space AABB around the object being rendered, we can then loop through all the pixels touched by the AABB in the smallest level of the HOM. We will then determine if an object completely shares the same screen space as the occluder or not. If it is neither (it only partially shares), we traverse up the HOM until we determine one of those or reach the last HOM level (at this point, we would just draw it). Interestingly enough, by making the checks a little less rigid, we can introduce approximate occlusion culling. If we ever determine complete coverage, the next step is to check the DEB. Notice that for each occluder, the DEB has a large rectangle with each pixel representing the value of the furthest depth. That means, if an object completely shares the same space as an occluder and that it is completely behind the depth given by the DEB, then it must be not visible. The next thing to do is find the closest depth to the viewer on the object, then scan pixels covered by the object’s screen space AABB and compare the closest depth to the depth read. If it always turns out to be behind, then the object is not visible.
Apologies for such a lengthy explanation, but it’s a long process. Hope you enjoy the demo below!