Do you want your avatar to be efficient and be loved by everyone because of all the frames you're saving them? Follow these tips and you should be good!
Any recommended numbers or limits in this document are subject to change at any time. Although some of the descriptions provided below are not precise in a technical manner, this document is intended to assist novice users in learning how to optimize their avatars.
Community-created tools like Cats Blender Plugin (MIT license) allow users to very easily optimize their models and assist with common VRChat avatar problems. We strongly recommend using tools like this! It makes your job easier, and improves performance for all.
As a sidenote, the SDK's Build Control panel provides numbers of components on avatars to help with optimization.
Dynamic Bones is a Unity Asset that you can purchase that allows you to define bones on your avatar's rig to move around as if they were hanging. You can also define static forces like gravity which can make hair fall more realistically.
Dynamic Bones runs on your processor, and can eat quite a bit of CPU time. It is also probably the most expensive single component you can put on your avatar. VRChat strongly recommends that you do not have any more than 30 affected transforms on any one avatar.
An "affected transform" is any bone that sits under the Dynamic Bone root bone and is not listed as (or a child of) an Exception under the Dynamic Bone component. So, if you've got a skirt that you're trying to add Dynamic Bones to with 16 bone chains that are 3 bones in length, that's a total of 48 affected transforms, which is far too many.
Again, VRChat recommends that you try to use Dynamic Bones so it affects 30 or fewer bones in total.
In addition, Dynamic Bone Colliders multiply the complexity of the calculation needed roughly by a factor of two. That means if you have a skirt with 48 affected transforms and a collider on each hand, it is a similar performance cost to having 144 affected Dynamic transforms. As such, VRChat strongly recommends against the use of Dynamic Bone Colliders. If you do use them, limit the number to one or two at most.
As an aside, you should never have more than one Dynamic Bone script affecting the same transform. The DB script will attempt to animate the bone twice, and will affect performance accordingly-- and Performance systems will take this into account.
Cloth is a default Unity component that has a similar cost to Dynamic Bones and is more difficult to set up. Limit your use of Cloth heavily, and do not apply it to meshes that have greater than 200 or so vertices.
If you want to use Dynamic Bones, check out our Dynamic Bones video below for best practices, as well as ways to reduce the number of bones in your Dynamic Bone chains.
There's two types of Mesh Renderers that your avatar could have on it-- Static Mesh Renderers and Skinned Mesh Renderers. Static Meshes do not deform. Skinned Meshes, however, usually have rigs (bones) that tell the engine how to move and deform the mesh based on the position of the bones. These Skinned Meshes are significantly more expensive, and you should only have one skinned Mesh Renderer on your avatar. There is very little reason to have more than one-- most of the time, additional items can be built into the original model.
On top of that, each additional mesh on your avatar incurs one or more additional "Draw Calls"-- essentially, time spent by your processor telling your graphics card to draw something on the screen.
Therefore, VRChat recommends that you have one Skinned Mesh Renderer at maximum, and 3 static mesh renderers at maximum. Merging meshes together is very simple in Blender, and is shown in the Meshes video below.
Finally, ensure that you're not using an excessive amount of triangles. The SDK will not permit you to upload a model that exceeds 70,000 triangles for PC. It is very rare that you need even this many polygons for details-- look into baking a normal map and simplifying your mesh via decimation or retopology.
Notably if you are using Cats Blender Plugin, it merges meshes automatically when you "Fix Model". If you seperate meshes by Material or by Loose Parts using Cats to assist with decimation or editing, do not forget to merge the meshes again.
Each additional material is also a draw call, which eats more processor time! If you have a lot of materials (more than 10), look into Texture Atlasing. With Community-created tools, atlasing is exceedingly easy. Check out the Materials video for more details.
As an aside, what is important is the number of material slots on the Renderer components in your avatar. If you have the same material in 20 slots, you still technically have 20 "materials".
This is due to the way that Unity splits meshes into submeshes. What really matters for performance is the number of submeshes created, which Unity creates based on Material slots.
Some shaders can cause excessive time spent rendering on the GPU. Try to stick with the Unity Standard shaders, or shaders that you know perform well. If you don't know how to tell if a shader is well-optimized, that's fine! Here are some examples-- these certainly aren't all the shaders available, but are all well-made and reasonably optimized with a variety of featuresets.
- Xiexe's "XSToon" Unity Shaders (GNU GPUv3) - A collection of PBR 'Toon' shaders for Unity.
- Silent's Shaders (MIT) - Shaders for Unity for cel shading, based off CubedParadox's Flat Lit Toon, featuring a number of handy features.
- NoeNoe's Shaders (Creative Commons 4.0) - A set of 'toon' shaders for VRChat intended to look good under any lighting.
- Cubed's Shaders (MIT) - A compilation of custom shaders for Unity3D in the 'flat-lit toon' style.
Speaking more technically, you want to avoid shaders that have excess shader passes. This incurs additional draw calls. This might be a bit too much for most users to worry about, so if you stick with commonly used and proven community shaders, that should suffice.
You should always avoid using shaders on avatars that use Tessellation. This is very common in "fur" shaders. Tessellation is a method by which your graphics card can take meshes and subdivide them for various effects. However, this effect is extremely expensive and will slow down even the most powerful of graphics cards. If you want a fur effect, consider looking into shaders that reproduce the effect without tessellation, such as XSFur.
You should also avoid shaders that use excessive amounts of shader keywords. This can cause serious and unpredictable issues with rendering your view in VRChat, and will fill your output log with a lot of redundant error messages. There is no need to include excessive shader keywords in your shader, so please only use the ones that are required for the features you are targeting.
Alpha transparency is also another expensive part of shaders-- typically you want to be using Cutout or Opaque modes on shaders. Transparency can be quite expensive, so only use it if you know what you're doing!
The Unity Profiler can be very useful when judging for how many draw calls you're incurring-- just make sure you turn off shadows on your Directional Light for a level playing field.
Even if you have a bunch of bones sitting in a scarf, skirt, or your hair that you're not using for anything, they can incur additional costs during skinning calls that your GPU has to worry about. If you're not going to use a bone, consider deleting the bone and merging it into the parent bone. If you want to know how to merge the weights of a bone into its parent, check out the video on Dynamic Bones above, which includes a part on bone merging.
Although particle systems can result in a lot of cool effects, having excessively large amounts of them can cause issues for some PCs. Limit the number of particle systems that you're using, and limit the maximum amount of particles emitting at any one given moment.
There are ways to have particle systems with large numbers of particles and retain performance. If you are interested in this, look into dynamic batching for sprite particles, don't use collision, and ensure the movement of your particles is simplistic.
If you're more technically inclined, you can try looking into Unity's Profiler view to judge how much CPU time your particle simulation is taking. Generally speaking, large transparent particles are worse than a lot of smaller, opaque ones. Unity's Particle System is actually quite optimized and runs quickly if used well.
Lights on avatars are real-time, and as such, are exceedingly expensive. Adding a light to your avatar means that everything that your Light touches will render with double the draw calls. Additional lights multiply the effect. This is obviously very bad for performance. Do not use Lights that are always on. Try using an Animation Override to turn a flashlight on and off, or alternately, do not use Lights at all.
If you do use a Light, turn off Shadows for the Light. Shadows on Realtime lights are VERY expensive and often don't look that great on something that moves around.
Particle Systems can be configured to have a light on for a number of particles. Never do this! Each particle with a light counts as a real-time light, which is (once again) extremely expensive.
In total, VRChat recommends that you do not use Lights of any type on avatars at all. Not only do they adversely affect your own avatar's performance, they multiply performance cost of avatars the light is hitting as well.
There's a large amount of software available to help you optimize your avatar and make it easier to build avatars.
For example, check out Pumkin's Avatar Tools (MIT) for the Unity Editor. Among other things, this Editor script allows you to quickly see stats on your avatars. This tool is in beta, and may have bugs-- please report any issues on Pumkin's GitHub.
The following software has not been authored by VRChat. Please read and respect the licensing provided with each individual product.