Mixed Reality Utility Kit - Placing Content in Your Space
Updated: Mar 14, 2025
Often, a developer might want to place an object in a room without a full room scan or need to interpret complex scene information. The user might do this for simple cases like placing a panel or viewing screen on a wall. We have provided a feature called Instant Placement that provides functionality which allows developers to get started quickly and not worry about all the different room complexity that they might encounter. This feature is described in the
following section.However, more complex features require full scene understanding and placement of walls, furniture, or other objects. For those use cases, see
Scene Based Placement.
Instant Placement
After completing this section, the developer should be able to attach objects (e.g. panels, decorations) to surfaces (e.g., tables, walls).
This section introduces Instant Placement, a method for placing objects on surfaces using raycast intersections with depth textures provided by the Depth API. This approach uses raycasting technique to find the intersection of virtual rays with physical environment, allowing objects to be placed instantly without the need for scanning the room. It’s ideal for instantly placing panels on walls or dropping objects onto tables.
Environment Raycasting provides basic scene understanding without relying on the Scene Model. By defining a ray origin and direction, you get the first intersection point with the environment. Although less structured than the Scene Model, this method suits certain use cases and bypasses the Space Setup process.
For a comprehensive example, consult the
“EnvironmentPanelPlacement” sample, located in the MRUK Samples. This sample takes into account edges and makes sure that there is enough room on the surface for placement. It also shows you how to implement controls to resize the object being placed.
For a more basic setup using instant placement, we are going to show how to place a simple cube using the position and orientation of the intersection of the ray. Create a Game Object that will manage the instant placement in your scene and attach a new MonoBehaviour script to it. Include the namespace Meta.XR.MRUtilityKit
and add the following code to it:
private EnvironmentRaycastManager _raycastManager;
// Assign the right controller anchor found under OVRCamera to this field
[SerializeField]
private Transform _rightControllerAnchor;
private void Awake()
{
// This will also add the Environment Depth Manager if not already present in the scene
_raycastManager = gameObject.AddComponent<EnvironmentRaycastManager>();
}
private void Update()
{
if (OVRInput.GetDown(OVRInput.RawButton.RIndexTrigger))
{
// Create a standard Unity ray, originating from your right controller, to later feed into the raycastManager
var ray = new Ray(_rightControllerAnchor.position, _rightControllerAnchor.forward);
// Check if ray hits the environment
if (_raycastManager.Raycast(ray, out var hit))
{
// Spawn a cube and set it's position and rotation to the point hit
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.SetPositionAndRotation(hit.point, Quaternion.LookRotation(hit.normal, Vector3.up));
cube.transform.localScale *= 0.1f;
// If MRUK's world locking is not active, spawn a spatial anchor at the cube's position. Then parent the cube to the spatial anchor.
if (MRUK.Instance?.IsWorldLockActive != true)
{
cube.AddComponent<OVRSpatialAnchor>();
}
}
}
}
Once you have saved and reloaded the script, you will need to drag the right controller anchor found under the OVRCamera game object to the _rightControllerAnchor
field in your newly created game object. In your application, you can replace the cube with the object of your choice.
That’s all there is to it. Your object should now be placed when the trigger is pressed based on the direction that the right trigger is pointing.
Note: When MRUK loads and initializes the scene, it also starts a World Locking feature which keeps anchors from drifting. Since we’re not loading the scene in this example and relying solely on Depth API, we don’t have this world locking feature available. To account for this, we spawn a spatial anchor and parent the object we wish to place inside the anchor game object. More information
here.