Scene Decorator sample overview
Updated: May 7, 2026
The Scene Decorator sample places decorative objects in a mixed reality environment by analyzing room geometry and applying configurable placement rules. It targets Unity developers building MR applications that position objects based on room geometry, furniture positions, and spatial constraints.
Note: The SceneDecorator API has been replaced by a newer API and may be removed in a future SDK version.
- Programmatically switch decoration styles using the ClearDecorations + Add + DecorateScene pattern
- Configure SceneDecoration ScriptableObjects with distribution algorithms and target surfaces
- Apply constraints (SpaceMapGPU, height masks, collider avoidance) to filter placement candidates
- How the SceneDecorator pipeline works: candidate generation → raycasting → constraint filtering → modifier application
- Respond to
MRUK room events (creation, updates, removal) by re-applying decorations
- Device: Meta Quest with Scene API enabled (captured room data)
- Development environment: Unity with Meta XR SDK configured
For SDK versions, build prerequisites, and setup instructions, see the sample README.
Clone or download the Unity-MRUtilityKitSample repository from GitHub and open the project in Unity. Navigate to Assets/MRUKSamples/SceneDecorator/SceneDecorator.unity and build to your Meta Quest device. On launch, the sample loads your captured room data and presents a world-space UI panel for selecting decoration styles. For detailed build instructions, see the sample README.
The sample consists of a controller script, four SceneDecoration configurations, and a set of prefabs.
| File / Scene | Purpose | Features demonstrated |
|---|
SceneDecorator.unity | Main scene with MRUK, SpaceMapGPU, and UI | Scene setup, MRUK integration, EffectMesh visualization |
SceneDecoratorSampleController.cs | Programmatic decoration switching and event handling | Decoration lifecycle, MRUK event subscriptions, keyboard shortcuts |
Floor1_Trees_GlobalMesh_Random_SpaceMap.asset | Random tree placement on floor using SpaceMapGPU | Random distribution, GlobalMesh targeting, collider avoidance |
Floor2_AppleTomatoes_PhysicsLayer_Grid.asset | Grid-based apple/tomato placement with height constraint | Grid distribution, PhysicsLayers targeting (raycast against anchor colliders), height filtering |
Walls.asset | Random rock placement on walls | Surface alignment, NotInside filtering |
Desk_SameRock_OnTableCouchBed.asset | Rock placement on furniture surfaces | Furniture targeting (table, couch, bed labels) |
When you launch the sample, MRUK loads your captured room data from the device. The EffectMesh creates a colored mesh visualization of the room geometry (walls, floor, ceiling).
The world-space UI panel displays eight buttons: Decoration 1–4, All Decorations, Clear Decorations, Toggle Mesh, and Launch Room Capture. Selecting a decoration style triggers the controller to clear existing objects, add the corresponding SceneDecoration to the decorator’s list, and call DecorateScene().
Behind the scenes, the SceneDecorator iterates over scene anchors matching the decoration’s label filter. For each anchor, the distribution algorithm (Grid or Random) generates candidate positions. Constraints filter out invalid candidates — for example, rejecting positions that overlap colliders or exceed a height threshold. Surviving candidates receive pooled prefabs, and modifiers adjust each object’s scale, rotation, and surface alignment.
If you update your room geometry via Space Setup, the sample automatically re-applies the current decoration style.
Decoration switching pattern
The controller drives decoration changes programmatically. Each decoration method follows the same three-step pattern — clear, add, decorate:
ClearDecorations();
Decorator.sceneDecorations.Add(GetDecorationByStyle(DecorationStyle.Floor1));
Decorator.DecorateScene();
The GetDecorationByStyle helper maps a DecorationStyle enum value to the corresponding SceneDecoration asset configured in the Inspector. See the complete implementation in SceneDecoratorSampleController.cs.
Event-driven re-decoration
The sample responds to MRUK room lifecycle events by re-applying the current decoration style. The controller subscribes to room creation, update, and removal events in Start():
MRUK.Instance.RoomCreatedEvent.AddListener(ReceiveCreatedRoom);
MRUK.Instance.RoomRemovedEvent.AddListener(ReceiveRemovedRoom);
MRUK.Instance.RoomUpdatedEvent.AddListener(ReceiveUpdatedRoom);
When any event fires, UpdateAfterEvent() re-applies the current decoration style. See the complete event handling logic in SceneDecoratorSampleController.cs.
SceneDecoration configuration
Each SceneDecoration ScriptableObject defines what to place, where to place it, and how to transform it. The Floor1 decoration demonstrates SpaceMapGPU integration: the SpaceMapGPUMask samples the SpaceMap texture at each candidate position, and the constraint rejects candidates in occupied areas (where the SpaceMap value falls outside the configured range). The ColliderMask provides an additional check, rejecting positions that overlap existing colliders. The Floor2 decoration uses a HeightMask constraint that filters candidates by height value (accepting values between 0 and 0.5), keeping apples and tomatoes at ground level. See the SceneDecoration assets in Assets/MRUKSamples/SceneDecorator/ScriptableObjects/.
SceneDecoration supports two targeting modes that can be combined: GlobalMesh (raycast against the combined room mesh) and PhysicsLayers (raycast against individual anchor colliders). The Desk decoration uses GlobalMesh targeting with a label filter (table, couch, bed) to place rocks only on furniture surfaces. The Walls decoration combines both GlobalMesh and PhysicsLayers targeting, and applies a NotInsideMask to filter out positions inside scene volumes such as furniture. See the target configuration in each SceneDecoration asset.
After spawning, the SceneDecorator applies modifiers to transform objects. The Floor1 decoration uses RotationModifierSpaceMap, which rotates trees toward nearby spatial features by sampling the SpaceMap around each object. The Walls decoration uses KeepUprightWithSurfaceModifier to align rocks to wall normals while keeping them upright. See the modifier configurations in the SceneDecoration assets.
- Add custom masks: Create a custom ScriptableObject by inheriting from the Mask class (see existing mask implementations in the SDK source) to filter candidates based on custom criteria, such as proximity to windows or distance from the room center.
- Combine distribution algorithms: Create a SceneDecoration that uses Grid distribution on horizontal surfaces and Random distribution on walls.
- Integrate with other samples: Combine SceneDecorator with the SpaceMap sample’s feature detection or the MultiSpawn sample’s interactive spawning.