177 lines
7.2 KiB
C#
177 lines
7.2 KiB
C#
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using Unity.Collections;
|
|
using Unity.Collections.LowLevel.Unsafe;
|
|
using UnityEngine;
|
|
using UnityEngine.XR.ARSubsystems;
|
|
using UnityEngine.XR.OpenXR;
|
|
|
|
namespace Microsoft.MixedReality.OpenXR
|
|
{
|
|
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
|
internal struct NativeAnchorData
|
|
{
|
|
public uint version; // == 1
|
|
public ulong anchorHandle; // OpenXR XrSpatialAnchor handle
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
|
internal struct NativeAnchor
|
|
{
|
|
public Guid id;
|
|
public Pose pose;
|
|
public TrackingState trackingState;
|
|
public IntPtr nativePtr; // pointer to NativeAnchorData
|
|
}
|
|
|
|
internal class AnchorSubsystem : XRAnchorSubsystem
|
|
{
|
|
public const string Id = "OpenXR Anchors Subsystem";
|
|
|
|
private class OpenXRProvider : Provider
|
|
{
|
|
public OpenXRProvider()
|
|
{
|
|
}
|
|
|
|
public override void Start()
|
|
{
|
|
NativeLib.StartAnchorSubsystem();
|
|
}
|
|
|
|
public override void Stop()
|
|
{
|
|
NativeLib.StopAnchorSubsystem();
|
|
}
|
|
|
|
public override void Destroy()
|
|
{
|
|
// If the anchor subsystem is destroyed, transient anchor data will be cleared, so the next time the
|
|
// subsystem is created, it will have a fresh new set of anchors. To preserve anchors, the app must use
|
|
// anchor persistence through the XRAnchorStore, or keep this subsystem alive.
|
|
NativeLib.DestroyAnchorSubsystem();
|
|
}
|
|
|
|
public unsafe override TrackableChanges<XRAnchor> GetChanges(XRAnchor defaultAnchor, Allocator allocator)
|
|
{
|
|
uint numAddedAnchors = 0;
|
|
uint numUpdatedAnchors = 0;
|
|
uint numRemovedAnchors = 0;
|
|
NativeLib.GetNumAnchorChanges(FrameTime.OnUpdate, ref numAddedAnchors, ref numUpdatedAnchors, ref numRemovedAnchors);
|
|
|
|
using (var addedNativeAnchors = new NativeArray<NativeAnchor>((int)numAddedAnchors, allocator, NativeArrayOptions.UninitializedMemory))
|
|
using (var updatedNativeAnchors = new NativeArray<NativeAnchor>((int)numUpdatedAnchors, allocator, NativeArrayOptions.UninitializedMemory))
|
|
using (var removedNativeAnchors = new NativeArray<Guid>((int)numRemovedAnchors, allocator, NativeArrayOptions.UninitializedMemory))
|
|
{
|
|
if (numAddedAnchors + numUpdatedAnchors + numRemovedAnchors > 0)
|
|
{
|
|
NativeLib.GetAnchorChanges(
|
|
(uint)(numAddedAnchors * sizeof(NativeAnchor)),
|
|
NativeArrayUnsafeUtility.GetUnsafePtr(addedNativeAnchors),
|
|
(uint)(numUpdatedAnchors * sizeof(NativeAnchor)),
|
|
NativeArrayUnsafeUtility.GetUnsafePtr(updatedNativeAnchors),
|
|
(uint)(numRemovedAnchors * sizeof(Guid)),
|
|
NativeArrayUnsafeUtility.GetUnsafePtr(removedNativeAnchors));
|
|
}
|
|
|
|
// Added Anchors
|
|
var addedAnchors = Array.Empty<XRAnchor>();
|
|
if (numAddedAnchors > 0)
|
|
{
|
|
addedAnchors = new XRAnchor[numAddedAnchors];
|
|
for (int i = 0; i < numAddedAnchors; ++i)
|
|
addedAnchors[i] = ToXRAnchor(addedNativeAnchors[i]);
|
|
}
|
|
|
|
// Updated Anchors
|
|
var updatedAnchors = Array.Empty<XRAnchor>();
|
|
if (numUpdatedAnchors > 0)
|
|
{
|
|
updatedAnchors = new XRAnchor[numUpdatedAnchors];
|
|
for (int i = 0; i < numUpdatedAnchors; ++i)
|
|
updatedAnchors[i] = ToXRAnchor(updatedNativeAnchors[i]);
|
|
}
|
|
|
|
// Removed Anchors
|
|
var removedAnchors = Array.Empty<TrackableId>();
|
|
if (numRemovedAnchors > 0)
|
|
{
|
|
removedAnchors = new TrackableId[numRemovedAnchors];
|
|
for (int i = 0; i < numRemovedAnchors; ++i)
|
|
removedAnchors[i] = FeatureUtils.ToTrackableId(removedNativeAnchors[i]);
|
|
}
|
|
|
|
TrackableChanges<XRAnchor> trackableChanges = TrackableChanges<XRAnchor>.CopyFrom(
|
|
new NativeArray<XRAnchor>(addedAnchors, allocator),
|
|
new NativeArray<XRAnchor>(updatedAnchors, allocator),
|
|
new NativeArray<TrackableId>(removedAnchors, allocator),
|
|
allocator);
|
|
return trackableChanges;
|
|
}
|
|
}
|
|
|
|
private XRAnchor ToXRAnchor(NativeAnchor nativeAnchor)
|
|
{
|
|
var anchorId = FeatureUtils.ToTrackableId(nativeAnchor.id);
|
|
return new XRAnchor(anchorId, nativeAnchor.pose, nativeAnchor.trackingState, nativeAnchor.nativePtr);
|
|
}
|
|
|
|
unsafe public override bool TryAddAnchor(Pose pose, out XRAnchor anchor)
|
|
{
|
|
NativeAnchor nativeAnchor = new NativeAnchor();
|
|
bool succeeded = NativeLib.TryAddAnchor(FrameTime.OnUpdate, pose.rotation, pose.position, UnsafeUtility.AddressOf(ref nativeAnchor));
|
|
anchor = ToXRAnchor(nativeAnchor);
|
|
return succeeded;
|
|
}
|
|
|
|
public override bool TryAttachAnchor(TrackableId trackableToAffix, Pose pose, out XRAnchor anchor)
|
|
{
|
|
return TryAddAnchor(pose, out anchor);
|
|
}
|
|
|
|
public override bool TryRemoveAnchor(TrackableId anchorId)
|
|
{
|
|
return NativeLib.TryRemoveAnchor(FeatureUtils.ToGuid(anchorId));
|
|
}
|
|
}
|
|
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
|
private static void RegisterDescriptor()
|
|
{
|
|
XRAnchorSubsystemDescriptor.Create(new XRAnchorSubsystemDescriptor.Cinfo
|
|
{
|
|
id = Id,
|
|
providerType = typeof(AnchorSubsystem.OpenXRProvider),
|
|
subsystemTypeOverride = typeof(AnchorSubsystem),
|
|
supportsTrackableAttachments = false
|
|
});
|
|
}
|
|
};
|
|
|
|
internal class AnchorSubsystemController : SubsystemController
|
|
{
|
|
private static List<XRAnchorSubsystemDescriptor> s_AnchorDescriptors = new List<XRAnchorSubsystemDescriptor>();
|
|
|
|
public AnchorSubsystemController(IOpenXRContext context) : base(context)
|
|
{
|
|
}
|
|
|
|
public override void OnSubsystemCreate(ISubsystemPlugin plugin)
|
|
{
|
|
if (OpenXRRuntime.IsExtensionEnabled("XR_MSFT_spatial_anchor"))
|
|
{
|
|
plugin.CreateSubsystem<XRAnchorSubsystemDescriptor, XRAnchorSubsystem>(s_AnchorDescriptors, AnchorSubsystem.Id);
|
|
}
|
|
}
|
|
|
|
public override void OnSubsystemDestroy(ISubsystemPlugin plugin)
|
|
{
|
|
plugin.DestroySubsystem<XRAnchorSubsystem>();
|
|
}
|
|
}
|
|
}
|