Develop

Mixed Reality Utility Kit – Manage and query scene data

Updated: Jul 6, 2026

Learning objectives

  • Configure the MRUK prefab to bootstrap scene data and define application behavior.
  • Stabilize your virtual scene using World Locking to minimize drift and simplify anchor workflows.
  • Select and combine data sources (Device, Prefab, JSON) with fallback strategies for development and production.
  • Control script execution order on scene-loaded events to manage complex initialization.
  • Leverage MRUK, MRUKRoom, MRUKAnchor, and MRUKTrackables APIs for spatial queries.

Scene capture and startup

To enable MRUK’s spatial queries, you must first generate a Scene Model using the Space Setup flow. This process captures planes, volumes, and mesh geometry of the physical environment.

Follow the on‑device Space Setup by navigating to Settings → Environment Setup → Space Setup. The guided scan walks users around their environment to capture necessary data, with a manual capture fallback if automatic detection struggles. You can also enable Load Scene on Startup in the MRUK prefab to auto‑trigger this flow, or call OVRScene.RequestSpaceSetup() programmatically.
Scene Capture Flow
  1. On-device Flow:
    • Navigate to Settings → Physical Space → Space Setup on the headset.
    • Follow the guided scan; if automatic detection struggles, switch to manual capture to outline key surfaces.
  2. Auto-trigger:
    • In the MRUK prefab inspector, enable Load Scene on Startup. If no scene exists, MRUK will prompt Space Setup at app launch.
  3. Programmatic Invocation:
    OVRScene.RequestSpaceSetup();
    
Link Limitation
Space Setup must run on‑device. You cannot perform Space Setup via Meta Horizon Link.

MRUK class

Place the MRUK.prefab (Core/Prefabs/MRUK.prefab) into your scene and configure its sections:

World Locking


World Locking keeps virtual content stationary relative to the real world without manually parenting every object to anchors. With EnableWorldLock (default true), MRUK applies subtle tracking‑space adjustments so anchors remain aligned. This allows your virtual objects to stay “static” in world space, improving stability and reducing the need to parent to each anchor.
World Locking Demo
  • EnableWorldLock (default: true): MRUK applies subtle camera-rig adjustments to maintain alignment.
  • When implementing custom camera control and World Locking is enabled, use the TrackingSpaceOffset transform matrix field in MRUK to move the tracking space.

Data source selection

MRUK supports three scene data inputs. Choose one or combine them via inspector dropdown or API:
  • Device: Live scan via OpenXR or XR Simulator. Reflects the user’s actual room.
  • Prefab: ~50 built-in sample rooms (Core/Rooms/Prefabs) for quick editor testing without scanning.
  • JSON: Pre-captured Scene Models (Core/Rooms/Json) for sharing or multiplayer synchronization.
Example API calls:
MRUK.Instance.LoadSceneFromDevice();
MRUK.Instance.LoadSceneFromPrefab("Office_Small");
MRUK.Instance.LoadSceneFromJson("MySavedScene.json");

Script execution order

Many initialization scripts depend on scene data. Under Script Execution, list your MonoBehaviours to fire on SceneLoadedEvent in the correct sequence. Here is the ordering of the FloorZone example:
  1. BasicWallDecorator: Apply color schemes or tags to primary walls.
  2. VolumeDecorator: Highlight furniture volumes or other semantic zones.
  3. FindSpawnPositions: Compute valid floor or surface points for gameplay elements.
This ordering guarantees that decorations are applied before spawn calculations run.

Working with scene data

After loading, MRUK exposes comprehensive APIs for querying rooms, anchors, and trackables.
  • MRUK: Singleton manager. Loads, clears, and raises global events.
  • MRUKRoom: Represents one scanned room—contains anchors and spatial utilities.
  • MRUKAnchor: Planes (walls, floor, ceiling), volumes (furniture), and mesh geometry with semantic labels.
  • MRUKTrackable: Dynamic anchors (e.g., keyboards) with detection events.
The rooms, anchors, and trackables that have been loaded by MRUK should never be deleted or modified from the outside. Doing so will lead to undefined behavior. See Effect Mesh and AnchorPrefabSpawner for more information on how to only visualize a specific room.
Events & Callbacks
Subscribe to:
  • MRUK.Instance.SceneLoadedEvent when all rooms finish loading.
  • RoomCreatedEvent / RoomUpdatedEvent as rooms change.
  • AnchorCreatedEvent / AnchorUpdatedEvent per‑anchor updates.
  • TrackableAdded / TrackableRemoved for dynamic trackables.

Typical workflow

Example: Placing a virtual billboard on the largest unobstructed wall.
// 1. Retrieve the current room
var currentRoom = MRUK.Instance.GetCurrentRoom();

// 2. Find the key wall (longest, unobstructed)
Vector2 wallScale;
var keyWall = currentRoom.GetKeyWall(out wallScale);

// 3. Create and align a quad
var quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
quad.transform.SetPositionAndRotation(
    keyWall.transform.position,
    keyWall.transform.rotation
);

quad.transform.localScale = new Vector3(wallScale.x, wallScale.y, 1f);

Core API reference


  // Scene loading & management
  void LoadSceneFromDevice();
  void LoadSceneFromPrefab(string prefabName);
  void LoadSceneFromJson(string jsonPath);
  void ClearScene();

  // Room queries
  List<MRUKRoom> GetRooms();
  MRUKRoom GetCurrentRoom();
  

  // Anchor collections
  List<MRUKAnchor> GetRoomAnchors();
  MRUKAnchor GetFloorAnchor();
  MRUKAnchor GetCeilingAnchor();
  List<MRUKAnchor> GetWallAnchors();

  // Spatial queries
  Vector2[] GetRoomOutline();
  MRUKAnchor GetKeyWall(out Vector2 scale);
  RaycastHit Raycast(Ray ray);
  bool IsPositionInRoom(Vector3 pos);
  Vector3 GenerateRandomPositionInRoom();
  

  // Hit testing
  bool Raycast(Ray ray);
  bool IsPositionInBoundary(Vector3 pos);

  // Geometry info
  float GetDistanceToSurface(Vector3 pos);
  Vector3 GetClosestSurfacePosition(Vector3 pos);
  Vector3 GetAnchorCenter();
  Vector3 GetAnchorSize();

  // Semantic labels
  string[] GetLabelsAsEnum();
  bool HasLabel(string label);
  
Best Practices
  • Always check MRUK.IsSupported before using MRUK APIs.
  • Cache room and anchor references when accessed frequently to reduce overhead.
  • Unsubscribe from events in OnDestroy() to prevent unexpected behaviour.
  • Never delete or modify MRUK room, anchor, or trackables. Instead use the functionality on EffectMesh and AnchorPrefabSpawner to only visualize a specific room.

Visualizing the scene with the EffectMesh class


EffectMesh creates special‑effect meshes from your Scene anchors—planes become triangulated meshes, volumes become cuboids, and the global scene mesh uses its raw geometry. You can apply custom UV mappings, vertex coloring, and optional colliders or hole‑cuts for doors and windows.
World Locking Demo

How to use

  • Drag the EffectMesh prefab (Core/Prefabs/EffectMesh.prefab) into your scene.
  • Assign a Mesh Material to define colors, outlines, or custom shaders.
  • Enable Add Colliders to allow physics interactions (for example, bouncing or placement checks).
  • Toggle Hide Mesh if you only need colliders or shader-driven effects without visible geometry.
  • Check Cut Holes to automatically remove quads where door and window frames appear.

EffectMesh settings

  • Spawn On Start: Controls whether an effect mesh is automatically applied to all rooms, a specific room, or no rooms, allowing for manual application if desired.
  • Mesh Material: Material applied to all generated primitives. Use multiple EffectMesh instances for layered materials.
  • Border Size: Thickness of edge bounds. Edge vertices are black, fading to white over this distance—ideal for outline shaders.
  • Frames Offset: Extrudes co-planar quads (doors/windows) off the wall by this many meters to prevent Z-fighting.
  • Add Colliders: When true, colliders are added to each mesh primitive.
  • Cast Shadows: Controls whether effect meshes cast shadows in the scene.
  • Hide Mesh: Hides the visual mesh but retains colliders and shader interactions.
  • Texture Coordinate Mode:
    • METRIC: UVs increase 1 unit per meter.
    • METRIC_SEAMLESS: 1 unit per meter, adjusted to end on integers to avoid seams.
    • MAINTAIN_ASPECT_RATIO: UVs scaled to preserve texture aspect ratio.
    • MAINTAIN_ASPECT_RATIO_SEAMLESS: Aspect-ratio UVs ending on whole numbers.
    • STRETCH: UVs mapped from 0 to 1 across each primitive.
  • Labels: List of semantic labels (for example, "Wall", "Floor", "GlobalMesh") to include in the generated meshes.

MRUKBase Sample
MRUKBase
A minimal scene with MRUK, EffectMesh (using the neon-blue RoomBoxEffects material with 1 m floor/ceiling crosses and stretched UVs), and SceneDebugger to visualize spatial queries.
View sample
BouncingBall
This sample uses EffectMesh colliders (hidden mesh) to let virtual balls bounce off the physical environment. BouncingBallMgr spawns balls on Grab and shoots them on Trigger; BouncingBallLogic plays collision audio and self-destructs after a delay.
View sample
BouncingBall Sample
Explore more MRUK documentation topics to dive deeper into spatial queries, content placement, manipulation, sharing, and debugging.

Core concepts

  • Overview Get an overview of MRUK’s key areas and features.
  • Getting Started Set up your project, install MRUK, and understand space setup with available Building Blocks.
  • Place Content without Scene Use Environment Raycasting to place 3D objects into physical space with minimal setup.
  • Place Content with Scene Data Use semantic anchors, surface scattering, and raycasting to place content precisely within mixed reality scenes.

Content and interaction

Track keyboards using MRUK-trackables.

Multiuser and debugging

MRUK samples and tutorials

Mixed reality design principles