Querying Planes
Note: This example uses the OpenXR version of the Magic Leap 2 Unity SDK. For a previous version using the Unity MLSDK, see here.
Permissions
In order to get access to plane finding on the Magic Leap 2, your project must have SPATIAL_MAPPING
enabled in project settings in addition to manually requesting permissions at runtime as demonstrated in the script below.
Scene Structure
The core necessary components to get access to planes in your scene are:
- Scene configured for OpenXR Magic Leap
- Enabled
Magic Leap 2 Plane Detection
under Project Settings > XR Plugin Management > OpenXR > Android > Magic Leap SPATIAL_MAPPING
permission enabled- MLRig with ARPlaneManager script attached
- Plane Prefab for ARPlaneManager
- Script making a MLXrPlaneSubsystem query
Example Script
The following script can be found in the Planes example scene in the Unity Examples package available on Magic Leap Hub.
using System;
using MagicLeap.Android;
using System.Collections;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
using MagicLeap.OpenXR.Features.Planes;
using MagicLeap.OpenXR.Subsystems;
using UnityEngine.XR.Management;
public class PlaneExample : MonoBehaviour
{
private MagicLeapPlanesFeature planeFeature;
private ARPlaneManager _planeManager;
[SerializeField, Tooltip("Maximum number of planes to return each query")]
private uint maxResults = 100;
[SerializeField, Tooltip("Minimum plane area to treat as a valid plane")]
private float minPlaneArea = 0.25f;
private Camera _camera;
private bool permissionGranted = false;
private IEnumerator Start()
{
_camera = Camera.main;
yield return new WaitUntil(AreSubsystemsLoaded);
_planeManager = FindObjectOfType<ARPlaneManager>();
if (_planeManager == null)
{
Debug.LogError("Failed to find ARPlaneManager in scene. Disabling Script");
enabled = false;
}
else
{
// disable planeManager until we have successfully requested required permissions
_planeManager.enabled = false;
}
permissionGranted = false;
// Request Spatial Mapping Permission
Permissions.RequestPermission( Permissions.SpatialMapping,
OnPermissionGranted,OnPermissionDenied,OnPermissionDenied);
}
private bool AreSubsystemsLoaded()
{
if (XRGeneralSettings.Instance == null) return false;
if (XRGeneralSettings.Instance.Manager == null) return false;
var activeLoader = XRGeneralSettings.Instance.Manager.activeLoader;
if (activeLoader == null) return false;
return activeLoader.GetLoadedSubsystem<XRPlaneSubsystem>() != null;
}
private void Update()
{
UpdateQuery();
}
private void UpdateQuery()
{
if (_planeManager != null && _planeManager.enabled && permissionGranted)
{
var newQuery = new MLXrPlaneSubsystem.PlanesQuery
{
Flags = _planeManager.requestedDetectionMode.ToMLXrQueryFlags() | MLXrPlaneSubsystem.MLPlanesQueryFlags.SemanticAll,
BoundsCenter = _camera.transform.position,
BoundsRotation = _camera.transform.rotation,
BoundsExtents = Vector3.one * 20f,
MaxResults = maxResults,
MinPlaneArea = minPlaneArea
};
MLXrPlaneSubsystem.Query = newQuery;
}
}
// Dispose of existing planes and stop scanning
public void OnDisable()
{
if (planeFeature != null && planeFeature.enabled)
{
planeFeature.InvalidateCurrentPlanes();
}
}
private void OnDestroy()
{
if(_planeManager)
_planeManager.enabled = false;
}
private void OnPermissionGranted(string permission)
{
_planeManager.enabled = true;
permissionGranted = true;
}
private void OnPermissionDenied(string permission)
{
Debug.LogError($"Failed to create Planes Subsystem due to missing or denied {Permissions.SpatialMapping} permission. Please add to manifest. Disabling script.");
enabled = false;
}
}
MLXrPlaneSubsystem Query Parameters
Flags | The flags to apply to this query. In the script above, this is set to SemanticAll, which includes SemanticCeiling, SemanticFloor, SemanticWall, SemanticPlatform |
BoundsCenter | The center of the bounding box which defines where planes extraction should occur. |
BoundsRotation | The rotation of the bounding box where planes extraction will occur. |
BoundsExtents | The size of the bounding box where planes extraction will occur. |
MaxResults | The maximum number of results that should be returned. |
MinPlaneArea | The minimum area (in squared meters) of planes to be returned. This value cannot be lower than 0.04 (lower values will be capped to this minimum). |
You can use the PlaneQuery example in conjunction with the Plane Classification example script added to the plane prefab in order to visually display differently classified planes in your space.