Passthrough Relighting sample overview
Updated: May 7, 2026
This sample demonstrates how to cast virtual shadows and highlights onto real-world surfaces in mixed reality using Mixed Reality Utility Kit (MRUK) EffectMesh and Unity’s lighting system. You explore dynamic lighting effects, runtime geometry switching, and passthrough manipulation to create convincing interactions between virtual objects and physical environments.
- Use EffectMesh to generate invisible shadow-receiving geometry from room data
- Switch between Scene Model geometry and Global Mesh geometry at runtime
- Configure directional lights and custom shader properties for virtual shadows and highlights on real-world surfaces
- Manipulate passthrough brightness and configure passthrough as underlay for mixed reality scenes
- Implement room-bounds checking with
MRUK for character respawn and locomotion safety
- Meta Quest device with passthrough support
- Unity Editor with Android build support
For SDK versions, build prerequisites, and detailed setup instructions, see the project README.
Clone the Unity MR Utility Kit Sample repository and open the project in Unity. Navigate to Assets/MRUKSamples/PassthroughRelighting and open the PassthroughRelighting.unity scene. Build the scene to your Meta Quest device following the standard Unity build process. For complete build instructions and troubleshooting, refer to the project README.
The sample consists of scene configuration, character controllers, UI components, and animation scripts that work together to demonstrate relighting effects.
| File / Scene | What it demonstrates | Key concepts |
|---|
PassthroughRelighting.unity | Complete scene setup with dual EffectMesh instances, passthrough underlay, and MRUK event wiring | SceneLoadedEvent initialization, passthrough configuration, directional lighting with soft shadows |
Scripts/UI/DebugPanel.cs | Runtime control panel for toggling shadows, highlights, geometry sources, and passthrough settings | EffectMesh geometry switching, shader property manipulation, OVRPassthroughLayer brightness control |
Scripts/OppyCharacterController.cs | Character locomotion with thumbstick input, jumping, and room-bounds safety | MRUK room queries, IsPositionInRoom validation, CharacterController teleportation
|
Scripts/OppyLightGlow.cs | Synchronized emission toggling that matches highlight state | Material emission property coordination |
FlameCharacter/FlameController.cs | Physics-based flame animation with dynamic light intensity | Rigidbody attraction forces, Perlin noise blend shapes, light intensity modulation |
Prefabs/UI/DebugPanel.prefab | Wrist-mounted UI with toggles and sliders | Runtime debugging interface for mixed reality |
When you launch the sample, passthrough displays your physical room as the background. MRUK loads your room data and generates invisible EffectMesh geometry matching your walls, floor, ceiling, and furniture.
Oppy spawns in front of you or at the room center. A flame character hovers above Oppy, attracted by physics forces while facing the camera. The directional light casts Oppy’s shadow onto the EffectMesh surfaces, creating realistic shadows on your real floor and walls. The flame’s point light creates highlight effects on nearby surfaces.
You control Oppy with the right thumbstick and can make Oppy jump. The wrist-mounted debug panel lets you toggle shadows, highlights, geometry sources (Scene Model vs. Global Mesh), light intensity, and passthrough brightness in real time.
Dual EffectMesh strategy for geometry switching
The sample creates two EffectMesh instances at scene load: one configured to exclude GLOBAL_MESH labels (showing individual room elements like walls and furniture), and one configured to show only GLOBAL_MESH labels (unified room geometry). The debug panel switches between them by calling CreateMesh() on one instance and DestroyMesh() on the other, avoiding the overhead of recreating both geometries. You can see this pattern in the GeometrySettingsChanged method in DebugPanel.cs.
For detailed EffectMesh API documentation, see the MRUK overview.
Shadow casting onto invisible geometry
The sample configures both EffectMesh instances with colliders enabled and castShadows disabled, so they receive shadows from the directional light without casting their own. The ShadowsSettingsChanged method in DebugPanel.cs toggles _oppyRenderer.shadowCastingMode between ShadowCastingMode.On and ShadowCastingMode.Off based on the shadow dropdown selection.
Material-based highlight effects
The sample applies highlight effects by modifying shader properties on the EffectMesh material. The debug panel calls SetFloat on _HighLightAttenuation and _HighlightOpacity to control intensity and blend. When highlights toggle on, OppyLightGlow synchronizes Oppy’s emission color, creating visual consistency between the character and surface effects. See the implementation in DebugPanel.cs and OppyLightGlow.cs.
Physics-based flame animation
The flame character uses three rigidbody segments with attraction forces targeting Oppy’s transform, combined with Perlin noise driving blend shape weights for organic flickering. Light intensity modulates based on the blend shape weights, creating dynamic lighting that responds to the flame’s animation. The sample implements this in FlameController.cs.
Room-bounds respawn with MRUK queries
On SceneLoadedEvent, the sample calls MRUK.Instance.GetCurrentRoom().IsPositionInRoom(position) to validate the respawn position. If invalid, it teleports Oppy to GetCurrentRoom().GetRoomBounds().center, disabling the CharacterController during the teleport to prevent physics conflicts. This pattern ensures characters stay within valid playspace boundaries. See the implementation in OppyCharacterController.cs.
- Modify the flame’s attraction force parameters in FlameController.cs to create different movement patterns, or retarget the attraction to follow the player’s hand instead of Oppy.
- Add multiple light sources with different colors and blend their highlight contributions on the EffectMesh material to simulate complex lighting scenarios.
- Replace Oppy with your own character model and adjust the shadow resolution, light angle, or add additional point lights to match your art style.
For more advanced geometry manipulation, explore the Destructible Mesh sample. For character navigation on MRUK surfaces, see the Nav Mesh sample.