The following blog post was written by Jasin Bushnaief of Umbra Software to explain the updates to occlusion culling in Unity Pro 4.3.
This is the last post in a three-post series. In the first one, I described the new occlusion culling system in Unity 4.3 and went through the basic usage and parameters. In the second one, I gave a list of best practices and general recommendations for getting the most out of Umbra. This last post deals with troubleshooting some common issues people tend to encounter when using Umbra.
Unity offers a couple of helpers for figuring out what’s going on in occlusion culling. These visualizations may help you figuring out why occlusion culling isn’t behaving quite as you’d expect. The visualizations can be found by enabling the Visualization pane in the Occlusion window and selecting the camera.
The individual visualizations can then be enabled and disabled in the Scene view, in the Occlusion Culling dialog.
Let’s take a look at what the different visualizations do.
The Camera Volumes visualization simply shows you, as a grey box, in which cell the camera is located. For more information on what the cells are, take a look at the first post. This is one way of figuring out how the value of smallest occluder changes the output resolution of the data, for instance. Also, if it looks like the cell bounds don’t make sense, for example when the cell incorrectly extends to the other side of what should be an occluding wall, something may be amiss.
The purpose of the Visibility Lines visualization is to show you the line of sight that Umbra sees. The way it works is that Umbra will project its depth buffer back into the scene and draw lines to the furthermost non-occluded points in the camera’s view. This may help you to figure out, for instance, which holes or gaps cause “leaks” in occlusion, ultimately causing some objects to become visible. This may also reveal some dubious situations where some object that clearly should be a good occluder, doesn’t occlude anything because of, say, forgetting to enable the static occluder flag for the object.
The Portals visualization will draw all the traversed portals as semi-transparent axis-aligned quads. Not only will this help you get an idea of how many portals Umbra traverses and thus help you deal with occlusion culling performance tweaking, but it also provides another way of looking at what’s in Umbra’s line of sight. So you can see if there are some spots in the scene that don’t really cause occlusion, and how the portals get placed into the scene in general.
While occlusion culling should just work in Unity, sometimes things don’t go quite as you’d expect. I’ll go over the most common issues people tend to run into, and how to solve those issues in order to make your game run smoothly.
Sometimes people wonder why some objects are reported visible by Umbra when in reality they seem to be occluded. There can be many reasons for this. The most important thing to understand is that Umbra is always conservative. This means that it always opts for objects being visible rather than invisible whenever there’s any uncertainty in the air. This applies to all tie-breaking situations as well.
Another thing to note is that the occlusion data represents a simplified version of the scene’s occluders. More specifically, it represents a conservatively simplified version, meaning some of the occlusion erodes and loses detail.
The level of detail that gets retained in the data is controlled by smallest occluder. Decreasing the value will produce higher-resolution data that should be less conservative, but at the same time, culling will lose some speed and the data will get larger.
Probably the most puzzling problematic scenario is when something gets reported by Umbra as occluded even though it shouldn’t be. After all the promises of always being conservative and never returning false negatives, how can this happen?
Well, there can be a couple of things going on. The first and by far the most common case is that you’re looking at something through a hole, gap or crack which gets solidified by Umbra’s voxelization. So typically the first thing you should try is to reduce the value of smallest hole and see if that fixes the issue. You can try temporarily tuning it down even quite a bit just to test if that’s the issue.
There are situations where this may not be completely obvious. For instance, if you have a book shelf in your scene where individual books are marked as occluders, too large a smallest hole may cause some of the books to be occluded either by the shelf or by the other books. So again, just decreasing the value of smallest hole is probably the first thing you should try.
Another case where objects may disappear is when your backface limit has been set to something less than 100 and your camera is in the vicinity of back-facing triangles. Note that the camera doesn’t have to actually be looking at the triangles nor do the triangles have to be facing away from the camera at that particular spot. It is enough that there is a topologically connected place (i.e. not behind a wall or anything) close to the camera from which some back-facing triangles can be seen.
The first thing to do to remedy this is obviously try with a backface limit of 100 and see if that fixes the issue. If it does, it may make sense to modify the geometry either by re-modeling some of the assets so that they’re two-sided or solid, or just removing the static occluder flag from the problematic objects. Or if you don’t care about the occlusion data size or don’t get a huge benefit out of the backface optimization, just disabling the backface test by setting the value at 100 is of course also an option.
Culling may behave strangely if your camera goes inside an occluder, or infinitesimally close to one. Typically this may occur in a game with a 3rd person camera. Because Umbra considers occluders as solid objects, culling from inside one will typically mean that most of the stuff in your scene will get culled. On the other hand, if the backface test has been enabled, many of the locations inside occluders will have been removed from the data altogether, yielding undefined results. So you should not let the camera go inside occluders!
To be more specific, in general Umbra will be able to guarantee correct culling when the camera is further away from an occluder than the value of smallest hole. In most cases, going even closer will still work, but in some cases, because the limitations the voxel resolution implies on the accuracy of the occlusion data, going super close to an occluder may result in the camera being incorrectly assigned to a location inside an occluder. Hint: use the “camera volume” visualization to see in which cell the camera is located and what it looks like.
Generally, when the backface test is enabled (i.e. when backface threshold is something smaller than 100), Umbra will do a better job near occluders, because it is able to detect the insides of occluders, and correspondingly dilate all valid locations slightly towards them, so that you’ll get correct results even if you go arbitrarily close to an occluder. So if you cannot prevent your camera from going very close (or even slightly inside) an occluder, the first thing you may wish to try is to set backface threshold to something smaller than 100. This will help with dilation and may fix the issue.
If tweaking backface threshold does not help, or if your camera goes very deep inside an occluder, the only thing left to do is to simply remove the occluder flag from the object.
The reason for slow culling is typically very simple. Umbra traverses too many portals, and thus the visibility query takes a long time. The parameter that controls the portal resolution in the occlusion data is smallest occluder. A larger value will produce a lower-resolution portal graph, which is generally faster to traverse, up to a point. There are some situations, however, where this is not the case. Specifically, when having to simplify the occluder data conservatively, sometimes the increased conservativity of a lower-resolution graph may cause the view distances to increase, and the total amount of traversed portals to increase with it as well. But this is not the most typical of situations. In general, a large smallest occluder value will produce data that is faster to process in the runtime, at the cost of reduced accuracy of the occlusion.
Another, but obviously a bit more arduous way of making sure that the number of traversed portals doesn’t get out of hand is to modify the geometry of the scene so that the view distances don’t get too long in the problematic areas. Manually inserting occlusion into open areas will of course cause the traverse to terminate sooner, reducing the amount of processed portals and thus making occlusion culling faster.
The speed of baking largely depends on one thing: the number of voxels that need to be processed. In turn, the number of processed voxels is defined by two factors: the dimensions of the scene and the voxel size. Assuming you can’t do much about the former, the latter you can easily control with the smallest hole parameter. A larger value will of course speed up baking. So, it may make sense to start with a relatively large value and then tune it down if your objects are incorrectly disappearing because of too aggressive occluder generation. A microscopic smallest hole may cause baking to take forever and/or to consume ridiculous amounts of memory.
If baking your scene produces too much occlusion data, there are a couple of things you can try. First, changing the value of backface limit to something smaller than 100, for instance 99, 50 or even 30 may be a good start. If you do this, make sure that culling works correctly in all areas your camera may be in. See the previous post for more information.
If changing backface limit is not an option, produces unpredictable results or doesn’t reduce the data size enough, you can try increasing the value of smallest occluder which determines the resolution of the occlusion data and thus has a very significant impact on the size. Note that increasing smallest occluder also increases the conservativity of the results.
Finally, it’s worth noting that huge scenes will naturally generate more occlusion data than small ones. The size of the occlusion data is displayed at the bottom of the Occlusion window.
In some rare cases, where the scene is vast in size and the smallest occluder parameter has been set to a super small value, Baking may fail with the error “Failure in split phase”. This occurs because the initial step of the bake tries to subdivide the scene into computation tiles. The subdivision is based on the smallest occluder parameter and when the scene is humongous in size (like, dozens of kilometers in each direction) too many computation tiles may be created, resulting in an out of memory error. This, in turn, manifests as “Failure in split phase” to the user. Increasing the value of smallest occluder and/or splitting up the scene into smaller chunks will get rid of this error.