Develop

Floor Zone sample overview

Updated: May 6, 2026

Overview

This sample demonstrates how to use MR Utility Kit (MRUK) to discover the largest unobstructed floor area in a room and place virtual content within it. The sample implements a virtual fishing pond that automatically positions itself on the largest open floor space, avoiding furniture and obstacles detected by the Scene API.

What you will learn

  • Use the FindSpawnPositions SDK component to discover valid floor positions
  • Cluster spawn points and identify the largest contiguous floor area
  • Scale virtual content dynamically based on discovered room dimensions
  • Respond to MRUK scene events for initialization and cleanup
  • Integrate passthrough rendering with spatial content placement

Requirements

  • Meta Quest device with passthrough support
  • Unity development environment with Meta XR SDK
  • Scene API setup and permissions
For detailed build prerequisites and SDK versions, see the sample README.
For Scene API setup instructions, see Scene API overview.

Get started

Clone or download the Unity-MRUtilityKitSample repository from GitHub. Open the project in Unity, navigate to the FloorZone scene at Assets/MRUKSamples/FloorZone/FindFloorZone.unity, and build to your Meta Quest device. When you run the scene, the virtual pond positions itself on the largest open floor area in your room. For build instructions and troubleshooting, see the sample README.

Explore the sample

The sample uses a three-phase approach to find and fit content to the largest unobstructed floor area: spawn floor markers across valid positions, cluster them to identify contiguous zones, and scale the virtual pond to fit the largest zone.
File / SceneWhat it demonstratesKey concepts
scripts/FishTank.cs
Core MRUK integration for room scaling and floor zone discovery
FindSpawnPositions, MRUKRoom, clustering, animation sequencing
scripts/FishingRod.cs
Controller input handling and haptic feedback
OVRInput integration, SetControllerVibration(), physics constraints
scripts/Fish.cs
AI behavior using Perlin noise and state machines
Procedural movement, bait attraction, stamina mechanics
FindFloorZone.unity
Scene structure with MRUK singleton and three floor zone spawners
MRUK event-driven initialization, Building Blocks passthrough integration
Prefabs: floorspot_*.prefab
Three sizes of floor markers (0.70m, 1.20m, 2m diameter)
Multi-resolution floor sampling

Runtime behavior

When you run the scene, passthrough activates and the Quest Scene API loads your room data. The EffectMesh component visualizes room surfaces based on MRUK scene data. Three sets of cylinder prefabs spawn on valid floor positions, avoiding furniture and obstacles. The virtual fish tank animates to match your room dimensions, then clusters the floor markers to identify the largest contiguous open area. The tank shrinks to fit that area, and a virtual pond appears with a fish swimming inside it. You can cast a fishing line using the controller, and the fish responds to the bait with attraction and hooking behavior.

Key concepts

Multi-resolution floor sampling

The sample spawns three different sizes of floor markers simultaneously: 30 small (0.70m), 15 medium (1.20m), and 10 large (2m) cylinders. Each size uses a separate FindSpawnPositions component configured to place prefabs on floor surfaces while avoiding obstacles. This multi-resolution approach ensures that the sample finds valid floor space regardless of room size. See FloorZone_Small, FloorZone_Medium, FloorZone_Large GameObjects in the scene hierarchy.
For more on spawn position configuration, see MR Utility Kit overview.

Event-driven initialization

The sample responds to MRUK lifecycle events to coordinate initialization. The events are wired through the Unity Inspector on the MRUK prefab, not in code. MRUK.SceneLoadedEvent triggers floor marker spawning and room mesh visualization. MRUK.RoomCreatedEvent triggers the clustering algorithm that selects the largest floor zone. MRUK.RoomRemovedEvent clears all spawned prefabs for cleanup. This event-driven approach decouples initialization timing from individual components. See FindFloorZone.unity for the event wiring in the scene hierarchy.

Floor zone clustering

The sample identifies the largest contiguous floor area using a flood-fill clustering algorithm. After all floor markers spawn, KeepOnlyBiggestPonds() collects spawned objects from each FindSpawnPositions component using the SpawnedObjects property. It recursively groups cylinders whose bounds overlap by at least 30%, calculates total volume for each cluster, keeps the largest, and destroys the rest. This ensures the pond fits in a single open area rather than spanning disconnected floor zones. See FishTank.cs for the clustering implementation.

Room-aware scaling

The sample scales the virtual pond in two phases using room dimensions from MRUKRoom.GetRoomBounds(). First, it expands to match the full room footprint. Then it shrinks to fit the discovered floor zone. Both animations use async/await with CancellationToken for clean cancellation and SmoothStep easing for natural motion. See FishTank.cs for the scaling logic.
For more on room bounds and spatial queries, see MR Utility Kit overview.

Stencil-masked rendering

The sample confines water and underwater effects to the pond area using stencil masking. A stencil shader renders at Geometry-1 queue, writes a stencil value with zero color output, and subsequent water shaders test that stencil to clip rendering. This prevents the water plane from visually extending beyond the discovered floor zone.

Extend the sample

  • Modify the clustering algorithm to prefer floor zones near specific room features (walls, windows) by querying MRUK anchor data
  • Add multiple content types with different size requirements and select the appropriate floor zone size dynamically
  • Integrate the floor zone discovery pattern into a furniture placement or room layout sample
For related MRUK patterns, see the Multi Spawn, Virtual Home, and Scene Decorator samples in the same repository.