Skip to main content
Version: 10 Jul 2024

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

FlagsThe flags to apply to this query. In the script above, this is set to SemanticAll, which includes SemanticCeiling, SemanticFloor, SemanticWall, SemanticPlatform
BoundsCenterThe center of the bounding box which defines where planes extraction should occur.
BoundsRotationThe rotation of the bounding box where planes extraction will occur.
BoundsExtentsThe size of the bounding box where planes extraction will occur.
MaxResultsThe maximum number of results that should be returned.
MinPlaneAreaThe 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.

Resources