Selective occlusion refers to the ability of objects (occluders) to hide other objects (ie not send them to the GPU). Implementation is identical to tree selection.
The selection of occlusion is not enabled by default because it is a feature that requires first understanding them to bring more benefits. If not used properly, could slow down the game. (Not too many, however, that processing time for self-regulating.)
How it Works
Selection occlusion activates when defining at least one "occluder" on stage. Occluder option is for physical buttons (physics)
The "Occluder" should be used only on network-based objects. As far as Physics is concerned, it is equivalent to "No collision". The reason why Occluder mode mutually exclusive with other physics mode is to emphasize on the fact that occluders should be specifically designed for that purpose and not every mesh should be an occluder. However, you can enable the Occlusion capability on physics objects using Python and Logic bricks. We'll come to that.
When an occluder object enters the view frustrum, the BGE builds a ZDepth buffer from the faces of that object. Whether the faces are one-side or two-side is important: only the front faces and two-side faces are used to build the ZDepth buffer. If multiple occluders are in the view frustrum, the BGE combines them and keeps the most foreground faces.
The resolution of the ZDepth buffer is controllable in the World settings with the "Occlu Res" button.
By default the resolution is 128 pixels for the largest dimension of the viewport while the resolution of the other dimension is set proportionally. Although 128 is a very low resolution, it is sufficient for the purpose of culling. The resolution can be increased to maximum 1024 but at great CPU expense.
The BGE traverses the DBVT tree and for each node checks if it is entirely hidden by the occluders and if so, culls the node (and all the objects it contains).
To further optimize the feature, the BGE builds and uses the ZDepth buffer only when at least one occluder is in the view frustrum. Until then, there is no performance decrease compared to regular view frustrum culling.
How to use them
There are situations where occlusion culling will not bring any benefit:
- If the occluders are small and don't hide many objects.
In that case, occlusion culling is just dragging your CPU down.
- If the occluders are large but hides simple objects.
In that case you're better off sending the objects to the GPU.
- If the occluders are large and hides many complex objects but in a very predictable way.
Example: a house full of complex objects. Although occlusion culling will perform well in this case, you will get better performance by implementing a specific logic that hides/unhides the objects; for instance making the objects visible only when the camera enters the house.
Occlusion culling makes most sense when the occluders are large objects (buildings, mountains, ...) that hide many complex objects in an unpredictable way. However, don't be too concerned about performance: even if you use it inappropriately, the performance decrease will be limited due to the structure of the algorithm.
Occluders can be visible graphic objects but beware that too many faces will make the ZDepth buffer creation slow. For example, a terrain is not a good candidate for occlusion: too many faces and too many overlap. Occluder can be invisible objects placed inside more complex objects (ex: "in the walls" of a building with complex architecture). Occluders can have "holes" through which you will see objects.
Here is a possible workflow to create occluders from a complex terrain:
- duplicate the terrain and make it low poly
- remove all horizontal parts and keep only the high elevation parts
- make all the face invisible and set the Occluder mode.
To optimize further, you may split the occluder into several objects (make an occluder from each mountain, each wall, etc.) and do the same for the terrain: this way, parts of the terrain that are behind occluders will not be rendered.
You can verify how the occlusion is working by running the game in wireframe mode.
You can turn on/off the occlusion capability of an object with Python:
obj.occlusion = True obj.setOcclusion(True, False) #param1=occlusion, param2=recurse in children
The object doesn't need to be defined as an occluder in the GUI: you can enable occlusion capability on any mesh object, including static and dynamic objects during the game.You can also use the Visibility Actuator:
Note that the layout of the actuator has changed: The Visible/Invisible mutually exclusive buttons have been replaced by two independent buttons: push the button to activate the feature (Visible/Occluding), unpush the button to activate the opposite feature (Invisible/Non-occluding).
Note that the actuator sets the Visibility and Occlusion mode at the same time. If you need to set them separately, use Python.
- If you want to use occlusion culling, you must at least have one occluder at the start of the game. The occluder doesn't need to be in an active layer. After that, you can enable and disable occlusion capability on every mesh objects during the game using on the In-game control.