Tutorial
Heading
Jan 21, 2021

Optimizing VRChat Worlds: occlusion culling

This guide focuses on the occlusion culling function of Unity and how to enhance scene performance by reducing texture sizes and hiding elements that aren’t visible

Premise

VRChat is a well-known social platform for all those who have VR equipment. Even if you don't have any specific hardware, you can still join the party from your standard PC screen! When you create a scenario, you need to be cautious about texture sizing and data management to ensure your scene runs smoothly for both you and the target audience.

If you neglect to democratize hardware requirements, you risk failing to create a popular VRChat World.

Mission

This guide focuses on the occlusion culling function of Unity and how to enhance scene performance by reducing texture sizes and hiding elements that aren’t visible. Additionally, we will discuss occlusion portals, although this scenario doesn't use any, as it is entirely outdoors with no enclosed areas.

Resources

  • Unity Editor (2018.4.20f1)

Please note that while this guide is VRChat-focused, the issue discussed is related to Unity Engine.

What is occlusion culling

Occlusion culling is a process that prevents Unity from performing rendering calculations for GameObjects that are completely hidden from view (occluded) by other GameObjects.

Every frame, a camera performs culling operations that examine the Renderers in the Scene and exclude (cull) those that do not need to be drawn. By default, Cameras perform frustum culling, which excludes all renderers that do not fall within the camera’s view frustum. However, frustum culling does not check whether a renderer is occluded by other GameObjects, and so Unity can still waste CPU and GPU time on rendering operations for renderers that are not visible in the final frame. Occlusion culling stops Unity from performing these wasted operations.

https://docs.unity3d.com/Manual/OcclusionCulling.html

This is basically the core knowledge of the whole system. This technique is used to avoid real-time calculations of GameObjects that are not in the camera frustrum. This improves framerate and event performance during runtime.

Occlusion culling on Unity 3D

How do you apply it to your scene

To begin creating an "occlusion area", you can either check the "static" box or click on the drop-down and toggle "OccluderStatic" and "OccludeeStatic". Another approach is to select the desired GameObjects and toggle the option in the Occlusion Window on the Object Panel.

Occlusion culling on Unity 3D
Occlusion culling on Unity 3D

This instructs the engine to consider the GameObject when calculating the Occlusion Data within its occlusion area (Unity considers the whole scene as a single area if you don't configure one prior to bake).

Occluders and occludees

The main difference between these two occlusion concepts is pretty simple, but it’s important to keep it in mind when building your scene’s occlusion areas and data.

  • An occluder is an object that can hide another object.
  • An occludee is an object that can be hidden from view by another object (occluder). If you uncheck this, the object will be considered differently, as if it were on another layer, not being hidden by other mesh renderers.

An example of occludee toggle would be for larger objects like grounds that should be considered separately to ensure they are always rendered.

Culling portals and culling areas

Culling Areas are "cube-shaped” volumes that "group" all the GameObjects inside of it, only being rendered if the camera is placed inside the same area. This works well if you have multiple enclosed areas. In our case, occlusion areas didn’t make sense as the whole scene is enclosed without visual walls among it.

Occlusion Portals are for connecting two occlusion areas so the camera can render both areas through the portal region area.

The toggle “open” option is for allowing or disallowing this connection.More info: https://docs.unity3d.com/2018.4/Documentation/Manual/class-OcclusionArea.html

100 Avatars world in VRChat top view

Occlusion culling area

Occlusion portal

Occlusion areas & portal

Alternatives to Unity's occlusion culling system

The occlusion system uses a built-in version of Umbra. Like any other system, it has its shortcomings and improvements compared to other occlusion system engines. For other projects, I personally have worked with Sector, an asset package found in the asset store that is very helpful and, at the time I worked with it, was superior to Unity's Umbra, primarly due to more flexible settings.

Another thing to keep in mind is the use of shaders with an excess of passes. Each pass is a complete mesh calculation for the material to be rendered, so materials with more than two passes can be problematic for lower platforms like mobile. I mention two as a minimum because transparent materials require two passes, and they also require the renderer to render what’s behind the mesh rendered with transparency, posing a significant challenge for low platforms.

Copy of batch example

Mesh render -> 1

Apply mat albedo -> 1

Apply mat transparency -> 1

Apply light -> 1

Please keep in mind that "static batching" combine meshes during runtime by the Unity engine, reducing the "mesh render" batching but maintaining material batching.

Occlusion in the Gauguin Avatar Garden

The entire scene is marked as "static" as there are no dynamic objects to consider (the water is animated through a material, not a shader). This made the occlusion set up "easy" and not very challenging for the initial steps. Keep in mind the size of the occluder box you want to set; the bigger it is, the less "accurate" it will be, but at the same time, the data will be much smaller. Each project needs its own balance.

In this case, for Gauguin, we set the size to 1.5, meaning that the smallest "box" packing objects was of 1.5 units (meters) in x/y/z value.

The “Smallest Hole” float is the setting to tell the camera how big the "hole" in the mesh has to be to start casting what is behind it. This is especially tricky on elements with small holes or meshes with complicated shapes.

The backface value is the value of directionality of a mesh to be rendered. The higher it is, the more "aggresive" the occluder will be, making the camera not compute meshes that are not facing towards it.

Bakeface

100 Avatars world in VRChat

Camera view

Camera view 02

Note that all the "black" shadows represents objects that are not getting rendered as their light bake remains on the mesh that is being rendered. Furthermore, you can see the "area" that the camera is in with the corresponding portals. When there is none in the scene, Unity creates them for you.

The best workaround is always to do it manually and never let the program do the math for you.

For the scene, the ground meshes were kept without the occludee option, as smaller avatars made it through the ground floor due to camera frustrum and its near clip (this cannot be changed, as it is how it goes in VRChat).

A live action of how the occlusion is working

Cocclunclusion

You may find occlusion culling easy to set up or even unnecessary! But the truth is that it is a vital piece during the final stages of environment development. It serves as the manager, loader and unloader of all the visual aspects of the camera, ensuring a smooth experience while maintaining the desired quality levels and keeping objects hidden from view but not unloaded from the scene to ensure fast loading and unloading.

Also, each time you modify a GameObject property like transform or add/remove GameObjects from the scene, you should rebuild your occlusion data, as those GameObjects are still "baked" in the data.

Keep it in mind, especially when working with large environments or low-spec platforms.

Feel free to drop any questions or share your try-outs and results!

VRChat
Kourtin
Head of OPS

I purr when you're not looking. I'm passionate about environments and all the techie stuff to make them look rad. Learning and improving everyday to be a better hooman.

Tutorial
How to import Decentraland SkyboxEditor into Unity
Tutorial
Doing a MANA transaction in a Decentraland scene
Tutorial
Canvas (2D UI) Manager in Decentraland