Luna's General Tips for optimizing VRChat worlds

Heya everyone,
After struggling a lot with worlds and breaking/optimizing things. Here is a collection of tips and pointers to make sure your VRChat world doesn’t tank performance.

Note, that everyone’s situation is different and some of these tips may not work for you. You should always see the pro’s and cons of doing things for yourself. But I do hope this will help a lot of developers get their footing with unity and making their worlds better.

Hidden performance eaters: Colliders

This is something a lot people, especially those new with Unity don’t notice. But the way you handle collision can impact performance in a big way.

Collision is basically what happens when one object interacts with another, without one you’ll pass straight through. So, we want colliders on things.
But what if I have this really complex thing that doesn’t really fit a box or a circle.
You might be tempted to just add a “Mesh Collider” and call it a day, but please resist the urge to do so.

Mesh Colliders are a huge performance eater, because they have to do a lot of complex math to calculate the physics.
If you can replace it with multiple box/sphere colliders, try that first.

If you can’t, try using the “convex” option, this reduces the number of “checks” the collider needs to do and will help with performance.

Visible performance eaters: Lighting

Lighting can be a huge performance eater as well, essentially each light has to calculate, well, lighting. And in most cases that math can be used for a lot of other things.

The only real light you can’t improve is your “Sun” which should be set to “Mixed”. Every other light can, and should be put to “static” and “baked”. This means that the objects around it will be baked onto a lightmap, giving it the look of lighting without actually having to do much math.

Additionally you should turn off Realtime Global Illumination, this can be a huge performance boost as well.

Hidden performance eater: Non-static objects

If it doesn’t move, put it on static, that’s the general rule of thumb for worlds.
Putting it on static tells unity that it doesn’t have to spend time to calculate a lot of things because the things aren’t moving. Non-static objects also don’t get included in a lightmap or reflection map. So, if it doesn’t ever move, put it on static!

Semi-Visible performance eater: Culling

This is something even experienced mappers will forget from time to time, object culling.

Object culling basically means that everything that’s not in view of the camera gets hidden. They’re still there, but well, if you can’t see it, why should the engine care to render it? Object culling can increase performance significantly and you should ALWAYS use it.

Culling can even be done for objects that aren’t static, like pick-ups.

Visible performance eater: LODS/High Polly

Although VRChat doesn’t really have a polygon limit, you should limit the amount of polygons in your scene. High detail objects/meshes can eat performance significantly. But well, sometimes you can’t get around it. If you need that one model, just make sure you use LODS.

Hidden Performance eater: Unused Animators/Rigs

Lets say you want to put your avatar in your world as a small Easter egg, that’s all fine, but if it doesn’t move remove the animator and skeleton from it.

Even if they don’t have an animation attached, animators and animation controllers can still slowly eat performance. Especially when you use a LOT of them. The performance win is usually low, but it does help.

Visible Performance eater: Reflection Captures

A reflection capture can add a lot to your scene, since it well, captures the reflections and casts them onto the objects around it.

But you should NEVER put them on realtime. ALWAYS put them on BAKED.

Visible Performance eater: Shaders

Keep an eye on your shader usage, some shaders can cause performance issues because they do complex math. It may look real nice but you should use the Profiler in unity and “Play Mode” to check what performance impact the shader has. Just toggle the objects with the specific shader on and off and see how your graph changes.

Visible performance eater: Pickups/Interactables

Having pickups and interactable elements in your world can make or break your world. Having a soft pillow to lay on, or a dice to throw can be a nice addition. However, do keep in mind where you place them and what you put on them.

Pickups usually require a collider. Make sure this is on the correct layer. Those being: Player, Pickup or PickupNoEnviroment. Also, NEVER use a mesh collider on a pickup. This can cause huge lag when they collide with something. Also, don’t make them drop at the start of your world, put them on something so they don’t jump around. Additionally you can disable their physics altogether by putting them on “Kinematic” and disabling “Gravity”

Visible performance eater: Post Processing

Don’t over-use post processing. Post Processing can have a major impact on your VRC World’s appearance but it can also impact performance a lot.

At the very least add a toggle to disable post processing.

General tips:

Udon/SDK2 Debugging tools:

Here’s the tools I generally use to debug my worlds:

  • VRWorld Toolkit: This tool helps fix most common performance issues, helps set up the proper things for post processing and allows you to see what’s making your box room eat up 300mb. It’s generally a tool I recommend anyone to use.
    GitHub - oneVR/VRWorldToolkit: Unity Editor extension for making VRChat worlds

  • CyanEmu: CyanEmu allows you to test your udon scripts or world while in Unity itself. No more build and play to see if things are broken, just do it all form unity real easy. It works with your custom udon code as well, and what’s better, it prints it out in your console!
    GitHub - CyanLaser/CyanEmu: CyanEmu is a VRChat client emulator in Unity. Includes a player controller with interact system. Works with SDK2 and SDK3.

  • VRChat itself: Obviously you can debug in vrchat itself. You just need to know the command line parameters for it. But! you can easily test your world as well without uploading to vrchat!
    Here’s the command line options I use while working on worlds:
    VRChat.exe --no-vr --enable-debug-gui --enable-sdk-log-levels --enable-udon-debug-logging "vrchat://create/?roomId=5471213064&hidden=true&name=BuildAndRun&url=file:///C://Users/<username>/AppData/Local/Temp/DefaultCompany/<projectname>/scene-standalonewindows64-<scene name>.vrcw"
    –no-vr prevents steam from starting steamVR the rest are self explanatory. More info:
    Launch Options
    Keyboard and Mouse

Reducing World Size

A common issue I see is people not really understanding how to reduce the file size of their world.
First off, I recommend using VRWorld Toolkit, since it actually shows you what’s taking up the space in your world.

Second, low hanging fruit, oversized textures.
Most textures can be 1k (1024), if not lower. Additionally you can turn on “crunch compression” to push the file size down even more.
Reflection Captures as well can be lowered to 512 resolution without issue in most cases as well.
Note that crunch compression shouldn’t be used on meshes, this messes with lighting and the file size gain on those is low at best.

Please note that I’ll expand this list with tips from others and my own experience as time goes on. If you have tips or advice of your own feel free to leave them here. But do know that this is my list of tips and tricks, this means that I could be wrong, or that I’m repeating things others have said before. This doesn’t make the things less valid, but do look at things yourself and experiment with things.