Run a VRChat World Optimization Pass

An optimization pass begins with evidence. Capture the problem in a repeatable scene, determine whether CPU time, GPU time, memory, loading, or build size is limiting the world, then change one relevant system and measure again.

This guide organizes the repair work. If you need an introduction to the Unity Profiler and frame timing first, read Measure and Improve VRChat World Performance.

Baseline, change, verify

Use the same location, camera route, active features, and platform before and after every change.

  1. Reproduce the slow scene and capture CPU, GPU, rendering, and memory evidence.
  2. Change one cost category that the evidence identifies.
  3. Repeat the capture and keep the change only when the target build improves without breaking the world.
Test the VRChat build

Unity Editor Play Mode is useful for quick comparisons, but Unity documents that Editor profiling is only an approximation. Verify important changes in VRChat on the intended PC, VR, Android, or Quest hardware and repeat tests with representative avatars and world features active.

Define the Test Scene

Write down the conditions before collecting numbers:

  • Unity scene and world version.
  • Build target: Windows or Android.
  • Test device and graphics settings.
  • Starting position and camera route.
  • Active mirror, video, particle, lighting, and post-processing states.
  • Number and type of test clients or representative avatars.
  • Whether the capture is Unity Play Mode, a development player, ClientSim, or VRChat Build & Test.

Use the same conditions for the comparison. A result from an empty desktop scene cannot replace a test of a crowded mirror area in VR.

Capture a Baseline

Open Window > Analysis > Profiler and record the problem long enough to include both normal frames and the slowdown. Start with the modules related to the suspected issue instead of enabling every profiling option.

Evidence What it helps identify
CPU Usage Scripts, physics, animation, rendering submission, and main-thread stalls
GPU Usage Expensive rendering work when GPU profiling is available
Rendering Draw calls, batches, triangles, vertices, and rendering activity
Memory Texture, mesh, audio, managed, and native memory pressure
Game view Statistics A quick view of batches, SetPass calls, geometry, and frame information
Frame Debugger The ordered rendering events that construct one frame

Do not enable Deep Profile by default. Unity warns that it adds overhead. Use normal samples and targeted call stacks first.

Record the original capture or write down the relevant values before editing the scene. A before-and-after comparison is more useful than an isolated number.

Identify the Limiting System

Evidence Likely area to inspect
CPU frame time is high Scripts, physics, animation, many active objects, or CPU rendering submission
GPU frame time is high Resolution, shaders, transparency, shadows, mirrors, post-processing, or excessive visible geometry
Batches or SetPass calls are high Material changes, many renderers, multiple passes, lights, shadows, or poor batching opportunities
Texture memory is high Oversized source textures, platform overrides, uncompressed formats, lightmaps, or duplicated content
Spikes occur during interaction Object activation, instantiation, video, network events, physics, or script work
Only one room is slow Visibility, mirrors, lights, particles, video, or dense content local to that room
Only Android is slow Mobile shaders, texture formats, transparency, geometry, lighting, or device memory limits

CPU and GPU work can overlap. Confirm which frame time controls the result before committing to a large visual rewrite.

Pass 1: Render Less

Unity's graphics guidance recommends reducing the number of objects rendered when visibility is the problem.

Check:

  • Camera far clipping distance.
  • Rooms, walls, corners, and other scene structure that block visibility.
  • Occlusion culling for static occluders and occludees.
  • LOD Groups for objects whose detail can decrease with screen size.
  • Renderer enable states for distant or optional areas.
  • Particle and effect bounds that are much larger than their visible result.

Do not combine the entire world into one mesh. Large combined meshes can remain visible when only a small part is on screen and can reduce the usefulness of occlusion culling. Group geometry according to rooms, visibility, materials, lightmapping, and replacement needs.

After baking occlusion data, test doors, windows, moving objects, mirrors, and viewpoints near occlusion boundaries. Missing or flickering geometry is not a performance improvement.

Pass 2: Review Materials and Draw Calls

Each renderer and material pass can contribute rendering work. Material count alone is not the complete draw-call count, but unnecessary material slots and shader passes are useful places to investigate.

  1. Use Rendering Statistics and the Frame Debugger at the slow viewpoint.
  2. Identify repeated renderers and material changes.
  3. Remove unused material slots.
  4. Reuse the same material asset where objects genuinely share settings and textures.
  5. Atlas related textures when it reduces materials without creating an oversized, inflexible mesh.
  6. Enable GPU instancing only on compatible repeated meshes and materials, then verify that Unity actually batches them.
  7. Recheck shadows and additional light passes affecting the objects.

VRChat's Android optimization guide warns against combining world materials and meshes too aggressively because Unity still needs useful object boundaries for batching and occlusion. Measure the actual result.

Pass 3: Reduce Texture and Lightmap Memory

Select important textures and review their Import Settings:

  • Max Size for each supported platform.
  • Compression format and quality.
  • Alpha channel requirement.
  • Mipmaps for textures viewed at changing distances.
  • Read/Write access, which should remain disabled unless a feature requires CPU access.
  • Normal-map type for normal textures.

Continue with Optimize Texture Imports in Unity 2022.3 for exact importer steps.

Also inspect:

  • baked lightmap count and resolution
  • reflection-probe cubemaps
  • video thumbnails and large UI textures
  • duplicate texture files from imported packages
  • textures included by unused scenes or prefabs

Crunch compression reduces downloaded or stored texture data, but VRChat's Android guide notes that it does not reduce the texture's in-memory size. Use platform texture formats and appropriate dimensions to address runtime memory.

Pass 4: Bake Static Lighting

VRChat recommends baked lighting for static world geometry and warns against overusing real-time lights.

  • Mark eligible geometry appropriately for the selected baking workflow.
  • Use baked or mixed lights according to the scene's actual dynamic-lighting needs.
  • Use light probes for moving objects that must respond to baked surroundings.
  • Remove decorative real-time lights that do not materially improve the scene.
  • Reduce shadow distance, range, and shadow-casting objects where real-time shadows remain necessary.
  • Check whether multiple pixel lights affect the same renderer.
  • Rebuild lighting and inspect lightmaps after changing geometry, UVs, or LODs.

Measure both the visual result and frame time. Baking transfers work away from runtime lighting but adds lightmap textures and build data, so lightmap settings still require review.

Pass 5: Simplify Shaders, Transparency, and Effects

GPU cost depends on shader work, the number of passes, the number of affected pixels, and how often pixels are redrawn.

Inspect:

  • transparent surfaces layered over each other
  • full-screen or screen-space effects
  • particles covering large areas
  • animated or multi-pass shaders
  • real-time reflections and reflection probes
  • materials with unused features enabled
  • effects visible through mirrors

VRChat's Android guidance recommends avoiding transparency where possible because it is costly on mobile GPUs. Use opaque or cutout solutions when they produce the required result.

Test custom shaders in stereo VR. A shader that looks correct in the Unity Game view may still be unsuitable for single-pass stereo rendering or the target mobile platform.

Pass 6: Control Mirrors, Video, and Extra Cameras

Mirrors and cameras render additional views. Video players add decoding, textures, audio, networking, and rendering work.

  • Keep optional mirrors inactive until a player requests them or approaches.
  • Limit mirror reflected layers and resolution.
  • Avoid multiple active mirrors showing the same busy room.
  • Disable unused video players rather than hiding only their display mesh.
  • Stop video and audio work when the feature is not in use.
  • Remove helper cameras that remain enabled after setup.
  • Test the combined case when mirrors can reflect video, particles, avatars, or transparent effects.

Use Create and Optimize Mirrors for VRChat Worlds for the current VRC_MirrorReflection controls.

Pass 7: Inspect Scripts, Physics, and Animation

When CPU Usage identifies non-rendering work:

  • Expand the expensive Profiler samples and locate the responsible system.
  • Disable the suspected object in a test copy and capture again.
  • Avoid work every frame when an event or state change can trigger it.
  • Reduce unnecessary active rigidbodies, joints, colliders, constraints, animators, and particles.
  • Prefer simple primitive colliders when they represent the required boundary.
  • Check whether disabled visual objects still have active scripts, audio, physics, or animation.
  • Review Udon networking separately when spikes correspond to ownership or synchronization.

Do not remove components based only on their presence. Capture the behavior and verify that the change affects the measured bottleneck.

Build Size and Runtime Memory Are Different

A smaller upload does not guarantee lower runtime memory or faster rendering.

Change Primarily affects
Crunch texture compression Download or package size
Texture dimensions and runtime compression format Runtime memory and bandwidth
Fewer shader variants or unused assets Build size and loading, depending on what the build includes
Fewer visible renderers and passes CPU/GPU rendering work
Baked lighting Runtime lighting cost, plus lightmap storage and memory
Occlusion culling Visible rendering work, plus occlusion-data storage

Review build size, runtime memory, and frame timing as separate results.

Create an Android-Specific Pass

Do not publish the unchanged Windows world as the Android version.

For Android and Quest:

  1. Switch to the Android platform through the VRChat SDK workflow.
  2. Apply Android texture overrides and supported mobile materials.
  3. Bake lighting and remove unsupported or excessively expensive effects.
  4. Reduce geometry, material, texture, transparency, particle, and physics cost for mobile hardware.
  5. Build and test on an Android or Quest device.
  6. Confirm the compressed world remains within VRChat's current Android world-size limit.

VRChat currently documents a 100 MB maximum compressed world size for Android. Treat the official Android pages as the source of truth because limits and platform behavior can change.

Verify the Completed Pass

  • The original slow scene was captured before changes.
  • The limiting CPU, GPU, memory, loading, or build-size category was identified.
  • Each retained change has a before-and-after result.
  • Spawn, social areas, mirrors, video areas, and other hotspots were retested.
  • Lighting, collisions, interactions, audio, and networking still work.
  • Windows and Android builds were optimized and tested separately where both are supported.
  • VR and desktop interaction paths were checked.
  • Representative avatars and enabled world features were included in the final test.
  • The project backup or version-control history can restore removed content.

Troubleshooting

The Profiler numbers change too much between tests

Use the same device, graphics settings, route, camera direction, world state, and active features. Capture several passes and compare representative sections rather than one isolated frame.

Play Mode improved, but the VRChat build did not

Editor profiling is approximate and does not reproduce the complete VRChat client. Recreate the test in Build & Test with the same mirror, avatar, video, and platform conditions, then investigate the limiting system shown there.

Draw calls increased after combining materials

Use the Frame Debugger to inspect the actual passes. Different shaders, keywords, light passes, shadows, material properties, or lost batching compatibility can prevent the expected reduction.

Occlusion culling makes objects disappear

Review the affected renderer's static flags, occlusion settings, bounds, and the baked occlusion data. Test openings and moving viewpoints, then rebake after correcting the scene setup.

The Android build is small but still uses too much memory

Package compression and runtime memory are different. Review texture dimensions, Android texture formats, mipmaps, lightmaps, meshes, and audio rather than relying on the compressed upload size.

Removing objects did not improve performance

The removed objects may not have contributed to the limiting system or may already have been culled. Return to the baseline capture, identify the largest relevant samples or rendering events, and test a change tied to that evidence.

Continue Learning

Official References

Next Step

Open Measure and Improve VRChat World Performance, capture a baseline at the slowest repeatable location, and select the first optimization pass from the limiting system.

Related Navigation