Virtual Home sample overview
Updated: May 6, 2026
This sample demonstrates how to replace a physical room with stylized virtual furniture and surfaces using MR Utility Kit’s AnchorPrefabSpawner system. It shows two spawning approaches: configuration-only spawners that require no custom code, and subclass spawners that extend base behavior with custom selection and alignment logic.
- Use AnchorPrefabSpawner to map Scene API anchor types to virtual prefabs
- Extend AnchorPrefabSpawner with custom selection, alignment, and post-spawn logic
- Use EffectMesh to render room surfaces with material effects and cut-hole support
- Respond to MR Utility Kit’s SceneLoadedEvent for scene-wide modifications
- Use bitwise filtering with
MRUKAnchor.Label to find anchors by type
- Meta Quest headset with a scanned room (use Space Setup to create a scene)
- Unity 2022.3 or later with Meta XR SDK and MR Utility Kit packages installed
For detailed setup instructions, see the sample README.
Clone the Unity-MRUtilityKitSample repository and open the project in Unity. Navigate to Assets/MRUKSamples/VirtualHome/VirtualHome.unity, build the scene to your Quest headset, and run the app in a room you have scanned with Space Setup. The sample loads your physical room data from Scene API and replaces walls, floor, ceiling, and furniture with virtual prefabs.
The sample project demonstrates spawning patterns through several spawner components and supporting scripts.
| File / Scene | What it demonstrates | Key concepts |
|---|
VirtualHome.unity | Main scene with MRUK singleton, EffectMesh surfaces, and five spawner components | Scene composition, spawner configuration, material effects |
BiggestAnchorPrefabSpawner.cs | Custom spawner that finds the largest anchor by volume and spawns a welcome UI on it | Custom prefab selection, bitwise label filtering, volume-based anchor ranking |
LightSpawner.cs | Custom spawner that adjusts ceiling lamp light range to match room dimensions | Post-spawn GameObject modification, room bounds queries |
RoomBasedMaterialTweak.cs | Event-driven shader property animation triggered by scene load | SceneLoadedEvent subscription, async material updates |
StickToVertex.cs | Attaches decorations to specific mesh vertices on furniture prefabs | Vertex-space transformations, parent scale compensation |
ResizableObjectsList.cs | ScriptableObject catalog of furniture prefabs with metadata (name, GUID, thumbnail) | Asset organization, spawner configuration data |
When you run the sample on a Meta Quest headset with a scanned room, you see your physical walls, floor, and ceiling replaced with stylized virtual materials. The walls have holes cut for doors and windows. Every piece of real furniture detected by Scene API is replaced with a corresponding virtual prefab: couches become VH_COUCH, tables become VH_TABLE, and so on. Plants randomize from four variants, and wall art randomizes from three variants.
A “Welcome to your virtual home” billboard panel appears on the largest couch in the room. A ceiling lamp spawns and adjusts its light range to fill the room based on its maximum extent. Blob shadows appear under furniture for visual grounding, and a depth-based gradient activates on materials as the scene loads.
Configuration-only spawning
The Spawner_VirtualHomeFurniture GameObject uses the base AnchorPrefabSpawner component directly, with no custom code. You configure 11 anchor-to-prefab mappings in the Inspector (couch, table, door frame, window frame, screen, storage, bed, lamp, other, plants, wall art). Floor and ceiling surfaces use separate EffectMesh components rather than the prefab spawner. The spawner iterates all anchors in the room and instantiates the matching prefab for each label. This approach works for straightforward one-to-one replacements.
See VirtualHome.unity, GameObject Spawner_VirtualHomeFurniture, Inspector configuration.
Custom prefab selection by volume
When configuration alone cannot express your spawning logic, subclass AnchorPrefabSpawner and override CustomPrefabSelection, which receives both the anchor and the configured prefab list. The BiggestAnchorPrefabSpawner class finds the largest anchor by volume area and returns a special welcome UI prefab for it, random prefabs for other anchors, or null for no spawn.
public override GameObject CustomPrefabSelection(MRUKAnchor anchor, List<GameObject> prefabs)
{
if (anchor == _biggestAnchor)
return BiggestPrefab;
if (prefabs == null || prefabs.Count == 0)
return null;
return prefabs[Random.Range(0, prefabs.Count)];
}
See BiggestAnchorPrefabSpawner.cs, method CustomPrefabSelection.
To find anchors of a specific type, use bitwise AND with MRUKAnchor.Label. The sample iterates all anchors, filters by the configured Labels bitmask, and compares volume bounds to identify the largest match.
foreach (var anchor in MRUK.Instance.GetCurrentRoom().Anchors) {
if ((Labels & anchor.Label) == 0) continue;
// Compare anchor.VolumeBounds...
}
See BiggestAnchorPrefabSpawner.cs, method BiggestAnchorForLabel.
To modify a spawned GameObject after instantiation, override SpawnPrefab, call the base implementation, retrieve the spawned object using AnchorPrefabSpawnerObjects.TryGetValue, and apply your changes. The LightSpawner class adjusts the light component’s range to the room’s maximum extent.
base.SpawnPrefab(anchorInfo);
AnchorPrefabSpawnerObjects.TryGetValue(anchorInfo, out var gameObject);
var roomBoundsSize = anchorInfo.Room.GetRoomBounds().size;
var maxExtent = Mathf.Max(roomBoundsSize.x, roomBoundsSize.y, roomBoundsSize.z);
gameObject?.GetComponentInChildren<Light>().range = maxExtent;
See LightSpawner.cs, method SpawnPrefab.
Event-driven scene modifications
To run logic after the scene loads, subscribe to MRUK.Instance.SceneLoadedEvent in OnEnable and unsubscribe in OnDisable. The RoomBasedMaterialTweak class uses this pattern to animate the _DistanceCovered shader property on all mesh renderers with a depth-based gradient effect.
See RoomBasedMaterialTweak.cs, methods OnEnable, OnDisable, StartTweakingAsync, and TweakDistanceBasedGradient.
- Add new furniture mappings: Create additional spawner configurations for Scene API labels not yet handled (e.g., GLOBAL_MESH or custom labels) and corresponding prefabs.
- Implement custom alignment logic: Override CustomPrefabAlignment in a spawner subclass to control how prefabs orient relative to anchor surfaces (e.g., align a painting flush with a wall anchor’s plane).
- Combine with relighting: Integrate the Passthrough Relighting sample’s virtual lighting system to cast shadows from your virtual furniture onto real surfaces.
For related spawning patterns, see the Multi Spawn sample. For foundational EffectMesh usage, see the MRUKBase sample.