Purpose: This page serves as a guide for world creators looking to implement custom-shaped VRChat mirrors that go beyond the standard Unity "Quad" geometry.
We will explore how to set up the necessary components to use a custom mesh as a reflective surface. Additionally, we will discuss the technical details of the 32-bit Layer Mask used by the native VRChat mirror script, helping you control exactly what is and isn't visible in the reflection.
Details: Unity 2022.3.22f1, VRChat SDK - Worlds 3.9.0, VRChat Package Resolver Tool 0.1.29, VRChat SDK - Base 3.9.0, ProBuilder 5.2.4.
Last Edit: 18 January 2026 (Baste~)
This guide details the composition and workflow for creating stable, custom-shaped mirrors in VRChat using the VRCSDK.
A VRChat mirror fundamentally consists of three key components, all of which are included in the VRCSDK and Unity:
Mesh Renderer: The standard Unity component that renders the geometry.
Mirror Reflection Material:
Location: Packages/com.vrchat.base/Runtime/VRCSDK/Sample Assets/Materials/MirrorReflection.mat
VRC Mirror Reflection Script:
Location: Packages/com.vrchat.worlds/Runtime/VRCSDK/Plugins/VRCSDK3.dll (This is typically the script component you add to the GameObject).
Not all meshes handle the reflection components well. Using specific creation techniques can significantly improve stability:
Recommended Tool: The "Poly Shape" tool from ProBuilder is highly effective.
Optimal Shape Language:
Create the shape with the correct number of vertices and 0 extrusion.
Ensure all vertices are individually snapped to a single, flat plane.
This technique enables more complex custom shapes (e.g., rounded mirrors) if the underlying mesh adheres to this flat-plane principle. Some non-flat object can even be made to work with varying degrees of success.
Rotation Stability: Objects with zero rotation (all 0s in the Transform component's Rotation fields) handles the VRC Mirror components best, rotation of the object holding the mirror material and script tends to mess with the mirror. Instead child the mirror to another object and then rotate the parent object.
These are the initial orientation and creation steps I have found for a successful mirror setup. Follow this workflow:
Create the Frame/Outline: Design the outline or frame for your desired mirror shape first.
Initial Alignment: Rotate your outline so that it is perpendicular and positioned directly in front of the VRCWorld GameObject (the scene origin).
Create Mirror Mesh: Use ProBuilder or your preferred tool (e.g., Poly Shape) to create the mirror surface object with the desired number of edges/vertices.
Clear Rotation: Go to the Transform component of the newly created mirror object and manually clear all rotation (set X, Y, and Z to 0).
Manual Vertex Alignment: Align the vertices of the clear-rotation mirror object with the frame:
Use Unity's Vertex Selection mode.
Tip: Hold "V" to enable vertex snapping for precise alignment.
Assign Components: Assign the MirrorReflection Material and the VRC Mirror Reflection Script to the aligned mirror object.
Parenting: Place the final mirror object as a child of a new, empty parent object.
Final Positioning: Use the parent object to handle all final rotation and movement for positioning the mirror in your scene.
Managing exactly which objects are visible in a VRChat mirror's reflection is handled using a 32-bit LayerMask. This mask is critical for performance because it tells the reflection camera which layers of objects it can skip rendering, saving significant resources.
This setting is referenced and modified in code using the mirror's script component, typically: VRC_MirrorReflection.m_ReflectLayers.
Every GameObject in a Unity scene is assigned to one of 32 possible layers (Layer 0 to Layer 31). The LayerMask is an integer where each of the 32 bits corresponds to a specific layer:
Layer 0: The first bit (rightmost) controls the visibility of Layer 0.
Layer 31: The last bit (leftmost) controls the visibility of Layer 31.
If a bit is set to 1, the corresponding layer is visible in the reflection; if it's set to 0, it is invisible.
// Create a variable for our VRC Mirror script that we will be modifying so that we can link it together in unity.
public VRC_MirrorReflection TargetMirrorScript;
// This lets us retrieve the 32-bit LayerMask in an int format. It is important to know that outputting this will give you the base-10 number not binary.
int CurrentBitMask = TargetMirrorScript.m_ReflectLayers.value;
//This code lets us make a int that will specify a single layer
Int Layer; //Takes a number (IE "6" for layer 6, "9" for layer 9)
int BitMask = 1 << Layer; // This left shifts a 1 based on which layer we are going to, Layer = 4 would be 10000 (Remember counting starts at 0)
//We can then take our designated layer and the CurrentBitMask and use the XOR operation to flip our chosen bit
int NewMask = CurrentBitMask ^ BitMask;
//Finally we can write our new mask back to the VRC_MirrorReflection script to change what layers are visible in game.
TargetMirrorScript.m_ReflectLayers = NewMask;