version 2.5.0
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
# XR_HTC_anchor XR_HTC_anchor_persistence
|
||||
## Name String
|
||||
XR_htc_anchor XR_HTC_anchor_persistence
|
||||
## Revision
|
||||
1
|
||||
## Overview
|
||||
|
||||
This document provides an overview of how to use the AnchorManager to manage anchors in an OpenXR application, specifically using the XR_HTC_anchor and XR_HTC_anchor_persistence extensions.
|
||||
Introduction
|
||||
|
||||
Anchors in OpenXR allow applications to track specific points in space over time. The XR_HTC_anchor extension provides the basic functionality for creating and managing anchors, while the XR_HTC_anchor_persistence extension allows anchors to be persisted across sessions. The AnchorManager class simplifies the use of these extensions by providing high-level methods for common operations.
|
||||
Checking Extension Support
|
||||
|
||||
Before using any anchor-related functions, it's important to check if the extensions are supported on the current system.
|
||||
|
||||
```csharp
|
||||
|
||||
bool isAnchorSupported = AnchorManager.IsSupported();
|
||||
bool isPersistedAnchorSupported = AnchorManager.IsPersistedAnchorSupported();
|
||||
|
||||
```
|
||||
|
||||
## Creating and Managing Anchors
|
||||
### Creating an Anchor
|
||||
|
||||
To create a new anchor, use the CreateAnchor method. This method requires a Pose representing the anchor's position and orientation relative to the tracking space, and a name for the anchor.
|
||||
|
||||
```csharp
|
||||
|
||||
Pose anchorPose = new Pose(new Vector3(0, 0, 0), Quaternion.identity);
|
||||
AnchorManager.Anchor newAnchor = AnchorManager.CreateAnchor(anchorPose, "MyAnchor");
|
||||
|
||||
```
|
||||
|
||||
### Getting an Anchor's Name
|
||||
|
||||
To retrieve the name of an existing anchor, use the GetSpatialAnchorName method.
|
||||
|
||||
```csharp
|
||||
|
||||
string anchorName;
|
||||
bool success = AnchorManager.GetSpatialAnchorName(newAnchor, out anchorName);
|
||||
if (success) {
|
||||
Debug.Log("Anchor name: " + anchorName);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Tracking Space and Pose
|
||||
|
||||
To get the current tracking space, use the GetTrackingSpace method. To retrieve the pose of an anchor relative to the current tracking space, use the GetTrackingSpacePose method.
|
||||
|
||||
```csharp
|
||||
|
||||
XrSpace trackingSpace = AnchorManager.GetTrackingSpace();
|
||||
Pose anchorPose;
|
||||
bool poseValid = AnchorManager.GetTrackingSpacePose(newAnchor, out anchorPose);
|
||||
if (poseValid) {
|
||||
Debug.Log("Anchor pose: " + anchorPose.position + ", " + anchorPose.rotation);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Persisting Anchors
|
||||
### Creating a Persisted Anchor Collection
|
||||
|
||||
To enable anchor persistence, create a persisted anchor collection using the CreatePersistedAnchorCollection method.
|
||||
|
||||
```csharp
|
||||
|
||||
Task createCollectionTask = AnchorManager.CreatePersistedAnchorCollection();
|
||||
createCollectionTask.Wait();
|
||||
|
||||
```
|
||||
|
||||
### Persisting an Anchor
|
||||
|
||||
To persist an anchor, use the PersistAnchor method with the anchor and a unique name for the persisted anchor.
|
||||
|
||||
```csharp
|
||||
|
||||
string persistedAnchorName = "MyPersistedAnchor";
|
||||
XrResult result = AnchorManager.PersistAnchor(newAnchor, persistedAnchorName);
|
||||
if (result == XrResult.XR_SUCCESS) {
|
||||
Debug.Log("Anchor persisted successfully.");
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Unpersisting an Anchor
|
||||
|
||||
To remove a persisted anchor, use the UnpersistAnchor method with the name of the persisted anchor.
|
||||
|
||||
```csharp
|
||||
|
||||
XrResult result = AnchorManager.UnpersistAnchor(persistedAnchorName);
|
||||
if (result == XrResult.XR_SUCCESS) {
|
||||
Debug.Log("Anchor unpersisted successfully.");
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Enumerating Persisted Anchors
|
||||
|
||||
To get a list of all persisted anchors, use the EnumeratePersistedAnchorNames method.
|
||||
|
||||
```csharp
|
||||
|
||||
string[] persistedAnchorNames;
|
||||
XrResult result = AnchorManager.EnumeratePersistedAnchorNames(out persistedAnchorNames);
|
||||
if (result == XrResult.XR_SUCCESS) {
|
||||
foreach (var name in persistedAnchorNames) {
|
||||
Debug.Log("Persisted anchor: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Creating an Anchor from a Persisted Anchor
|
||||
|
||||
To create an anchor from a persisted anchor, use the CreateSpatialAnchorFromPersistedAnchor method.
|
||||
|
||||
```csharp
|
||||
|
||||
AnchorManager.Anchor trackableAnchor;
|
||||
XrResult result = AnchorManager.CreateSpatialAnchorFromPersistedAnchor(persistedAnchorName, "NewAnchor", out trackableAnchor);
|
||||
if (result == XrResult.XR_SUCCESS) {
|
||||
Debug.Log("Anchor created from persisted anchor.");
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Exporting and Importing Persisted Anchors
|
||||
### Exporting a Persisted Anchor
|
||||
|
||||
To export a persisted anchor to a buffer, use the ExportPersistedAnchor method.
|
||||
|
||||
```csharp
|
||||
|
||||
Task<(XrResult, string, byte[])> exportTask = AnchorManager.ExportPersistedAnchor(persistedAnchorName);
|
||||
exportTask.Wait();
|
||||
var (exportResult, exportName, buffer) = exportTask.Result;
|
||||
if (exportResult == XrResult.XR_SUCCESS) {
|
||||
// Save buffer to a file or use as needed
|
||||
File.WriteAllBytes("anchor.pa", buffer);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Importing a Persisted Anchor
|
||||
|
||||
To import a persisted anchor from a buffer, use the ImportPersistedAnchor method.
|
||||
|
||||
```csharp
|
||||
|
||||
byte[] buffer = File.ReadAllBytes("anchor.pa");
|
||||
Task<XrResult> importTask = AnchorManager.ImportPersistedAnchor(buffer);
|
||||
importTask.Wait();
|
||||
if (importTask.Result == XrResult.XR_SUCCESS) {
|
||||
Debug.Log("Anchor imported successfully.");
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Clearing Persisted Anchors
|
||||
|
||||
To clear all persisted anchors, use the ClearPersistedAnchors method.
|
||||
|
||||
```csharp
|
||||
|
||||
XrResult result = AnchorManager.ClearPersistedAnchors();
|
||||
if (result == XrResult.XR_SUCCESS) {
|
||||
Debug.Log("All persisted anchors cleared.");
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
The AnchorManager class simplifies the management of anchors in OpenXR applications. By using the methods provided, you can easily create, persist, and manage anchors, ensuring that spatial data can be maintained across sessions. This document covers the basic operations; for more advanced usage, refer to the OpenXR specification and the implementation details of the AnchorManager class.
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright HTC Corporation All Rights Reserved.
|
||||
// Copyright HTC Corporation All Rights Reserved.
|
||||
|
||||
// Remove FAKE_DATA if editor or windows is supported.
|
||||
#if UNITY_EDITOR
|
||||
@@ -10,222 +10,666 @@ using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using UnityEngine.XR.OpenXR.Features;
|
||||
using VIVE.OpenXR.Feature;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.XR.OpenXR.Features;
|
||||
#endif
|
||||
|
||||
namespace VIVE.OpenXR.Anchor
|
||||
namespace VIVE.OpenXR.Feature
|
||||
{
|
||||
using XrPersistedAnchorCollectionHTC = System.IntPtr;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[OpenXRFeature(UiName = "VIVE XR Anchor",
|
||||
Desc = "VIVE's implementaion of the XR_HTC_anchor.",
|
||||
Company = "HTC",
|
||||
DocumentationLink = "..\\Documentation",
|
||||
OpenxrExtensionStrings = kOpenxrExtensionString,
|
||||
Version = "1.0.0",
|
||||
BuildTargetGroups = new[] { BuildTargetGroup.Android },
|
||||
FeatureId = featureId
|
||||
)]
|
||||
[OpenXRFeature(UiName = "VIVE XR Anchor (Beta)",
|
||||
Desc = "VIVE's implementaion of the XR_HTC_anchor.",
|
||||
Company = "HTC",
|
||||
DocumentationLink = "..\\Documentation",
|
||||
OpenxrExtensionStrings = kOpenxrExtensionString,
|
||||
Version = "1.0.0",
|
||||
BuildTargetGroups = new[] { BuildTargetGroup.Android, BuildTargetGroup.Standalone },
|
||||
FeatureId = featureId
|
||||
)]
|
||||
#endif
|
||||
public class ViveAnchor : OpenXRFeature
|
||||
{
|
||||
public const string kOpenxrExtensionString = "XR_HTC_anchor";
|
||||
/// <summary>
|
||||
/// The feature id string. This is used to give the feature a well known id for reference.
|
||||
/// </summary>
|
||||
public const string featureId = "vive.wave.openxr.feature.htcanchor";
|
||||
private XrInstance m_XrInstance = 0;
|
||||
private XrSession session = 0;
|
||||
private XrSystemId m_XrSystemId = 0;
|
||||
public class ViveAnchor : OpenXRFeature
|
||||
{
|
||||
public const string kOpenxrExtensionString = "XR_HTC_anchor XR_EXT_future XR_HTC_anchor_persistence";
|
||||
|
||||
#region struct, enum, const of this extensions
|
||||
/// <summary>
|
||||
/// The feature id string. This is used to give the feature a well known id for reference.
|
||||
/// </summary>
|
||||
public const string featureId = "vive.openxr.feature.htcanchor";
|
||||
|
||||
public struct XrSystemAnchorPropertiesHTC
|
||||
{
|
||||
public XrStructureType type;
|
||||
public System.IntPtr next;
|
||||
public XrBool32 supportsAnchor;
|
||||
}
|
||||
/// <summary>
|
||||
/// Enable or disable the persisted anchor feature. Set it only valid in feature settings.
|
||||
/// </summary>
|
||||
public bool enablePersistedAnchor = true;
|
||||
private XrInstance m_XrInstance = 0;
|
||||
private XrSession session = 0;
|
||||
private XrSystemId m_XrSystemId = 0;
|
||||
private bool IsInited = false;
|
||||
private bool IsPAInited = false;
|
||||
private bool useFakeData = false;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
public struct XrSpatialAnchorNameHTC
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
||||
public string name;
|
||||
}
|
||||
#region struct, enum, const of this extensions
|
||||
|
||||
public struct XrSpatialAnchorCreateInfoHTC
|
||||
{
|
||||
public XrStructureType type;
|
||||
public System.IntPtr next;
|
||||
public XrSpace space;
|
||||
public XrPosef poseInSpace;
|
||||
public XrSpatialAnchorNameHTC name;
|
||||
}
|
||||
/// <summary>
|
||||
/// An application can inspect whether the system is capable of anchor functionality by
|
||||
/// chaining an XrSystemAnchorPropertiesHTC structure to the XrSystemProperties when calling
|
||||
/// xrGetSystemProperties.The runtime must return XR_ERROR_FEATURE_UNSUPPORTED if
|
||||
/// XrSystemAnchorPropertiesHTC::supportsAnchor was XR_FALSE.
|
||||
/// supportsAnchor indicates if current system is capable of anchor functionality.
|
||||
/// </summary>
|
||||
public struct XrSystemAnchorPropertiesHTC
|
||||
{
|
||||
public XrStructureType type;
|
||||
public System.IntPtr next;
|
||||
public XrBool32 supportsAnchor;
|
||||
}
|
||||
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// name is a null-terminated UTF-8 string whose length is less than or equal to XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct XrSpatialAnchorNameHTC
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
|
||||
public byte[] name;
|
||||
|
||||
#region delegates and delegate instances
|
||||
delegate XrResult DelegateXrCreateSpatialAnchorHTC(XrSession session, ref XrSpatialAnchorCreateInfoHTC createInfo, ref XrSpace anchor);
|
||||
delegate XrResult DelegateXrGetSpatialAnchorNameHTC(XrSpace anchor, ref XrSpatialAnchorNameHTC name);
|
||||
public XrSpatialAnchorNameHTC(string anchorName)
|
||||
{
|
||||
name = new byte[256];
|
||||
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(anchorName);
|
||||
Array.Copy(utf8Bytes, name, Math.Min(utf8Bytes.Length, 255));
|
||||
name[255] = 0;
|
||||
}
|
||||
|
||||
DelegateXrCreateSpatialAnchorHTC XrCreateSpatialAnchorHTC;
|
||||
DelegateXrGetSpatialAnchorNameHTC XrGetSpatialAnchorNameHTC;
|
||||
#endregion delegates and delegate instances
|
||||
public XrSpatialAnchorNameHTC(XrSpatialAnchorNameHTC anchorName)
|
||||
{
|
||||
name = new byte[256];
|
||||
Array.Copy(anchorName.name, name, 256);
|
||||
name[255] = 0;
|
||||
}
|
||||
|
||||
#region override functions
|
||||
/// <inheritdoc />
|
||||
protected override IntPtr HookGetInstanceProcAddr(IntPtr func)
|
||||
{
|
||||
Debug.Log("ViveAnchor HookGetInstanceProcAddr() ");
|
||||
return ViveInterceptors.Instance.HookGetInstanceProcAddr(func);
|
||||
}
|
||||
public override readonly string ToString() {
|
||||
if (name == null)
|
||||
return string.Empty;
|
||||
return System.Text.Encoding.UTF8.GetString(name).TrimEnd('\0');
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool OnInstanceCreate(ulong xrInstance)
|
||||
{
|
||||
//Debug.Log("VIVEAnchor OnInstanceCreate() ");
|
||||
if (!OpenXRRuntime.IsExtensionEnabled(kOpenxrExtensionString))
|
||||
{
|
||||
Debug.LogWarning("ViveAnchor OnInstanceCreate() " + kOpenxrExtensionString + " is NOT enabled.");
|
||||
return false;
|
||||
}
|
||||
public struct XrSpatialAnchorCreateInfoHTC
|
||||
{
|
||||
public XrStructureType type;
|
||||
public System.IntPtr next;
|
||||
public XrSpace space;
|
||||
public XrPosef poseInSpace;
|
||||
public XrSpatialAnchorNameHTC name;
|
||||
}
|
||||
|
||||
m_XrInstance = xrInstance;
|
||||
//Debug.Log("OnInstanceCreate() " + m_XrInstance);
|
||||
CommonWrapper.Instance.OnInstanceCreate(xrInstance, xrGetInstanceProcAddr);
|
||||
SpaceWrapper.Instance.OnInstanceCreate(xrInstance, CommonWrapper.Instance.GetInstanceProcAddr);
|
||||
public struct XrPersistedAnchorCollectionAcquireInfoHTC
|
||||
{
|
||||
public XrStructureType type;
|
||||
public System.IntPtr next;
|
||||
}
|
||||
|
||||
return GetXrFunctionDelegates(m_XrInstance);
|
||||
}
|
||||
public struct XrPersistedAnchorCollectionAcquireCompletionHTC
|
||||
{
|
||||
public XrStructureType type;
|
||||
public System.IntPtr next;
|
||||
public XrResult futureResult;
|
||||
public System.IntPtr persistedAnchorCollection;
|
||||
}
|
||||
|
||||
protected override void OnInstanceDestroy(ulong xrInstance)
|
||||
{
|
||||
CommonWrapper.Instance.OnInstanceDestroy();
|
||||
SpaceWrapper.Instance.OnInstanceDestroy();
|
||||
}
|
||||
public struct XrSpatialAnchorPersistInfoHTC
|
||||
{
|
||||
public XrStructureType type;
|
||||
public System.IntPtr next;
|
||||
public XrSpace anchor;
|
||||
public XrSpatialAnchorNameHTC persistedAnchorName;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnSessionCreate(ulong xrSession)
|
||||
{
|
||||
Debug.Log("ViveAnchor OnSessionCreate() ");
|
||||
public struct XrSpatialAnchorFromPersistedAnchorCreateInfoHTC
|
||||
{
|
||||
public XrStructureType type;
|
||||
public System.IntPtr next;
|
||||
public System.IntPtr persistedAnchorCollection;
|
||||
public XrSpatialAnchorNameHTC persistedAnchorName;
|
||||
public XrSpatialAnchorNameHTC spatialAnchorName;
|
||||
}
|
||||
|
||||
// here's one way you can grab the session
|
||||
Debug.Log($"EXT: Got xrSession: {xrSession}");
|
||||
session = xrSession;
|
||||
}
|
||||
public struct XrSpatialAnchorFromPersistedAnchorCreateCompletionHTC
|
||||
{
|
||||
public XrStructureType type;
|
||||
public System.IntPtr next;
|
||||
public XrResult futureResult;
|
||||
public XrSpace anchor;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnSessionBegin(ulong xrSession)
|
||||
{
|
||||
Debug.Log("ViveAnchor OnSessionBegin() ");
|
||||
Debug.Log($"EXT: xrBeginSession: {xrSession}");
|
||||
}
|
||||
public struct XrPersistedAnchorPropertiesGetInfoHTC
|
||||
{
|
||||
public XrStructureType type;
|
||||
public System.IntPtr next;
|
||||
public uint maxPersistedAnchorCount;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnSessionEnd(ulong xrSession)
|
||||
{
|
||||
Debug.Log("ViveAnchor OnSessionEnd() ");
|
||||
Debug.Log($"EXT: about to xrEndSession: {xrSession}");
|
||||
}
|
||||
#endregion
|
||||
|
||||
// XXX Every millisecond the AppSpace switched from one space to another space. I don't know what is going on.
|
||||
//private ulong appSpace;
|
||||
//protected override void OnAppSpaceChange(ulong space)
|
||||
//{
|
||||
// //Debug.Log($"VIVEAnchor OnAppSpaceChange({appSpace} -> {space})");
|
||||
// appSpace = space;
|
||||
//}
|
||||
#region delegates and delegate instances
|
||||
public delegate XrResult DelegateXrCreateSpatialAnchorHTC(XrSession session, ref XrSpatialAnchorCreateInfoHTC createInfo, ref XrSpace anchor);
|
||||
public delegate XrResult DelegateXrGetSpatialAnchorNameHTC(XrSpace anchor, ref XrSpatialAnchorNameHTC name);
|
||||
public delegate XrResult DelegateXrAcquirePersistedAnchorCollectionAsyncHTC(XrSession session, ref XrPersistedAnchorCollectionAcquireInfoHTC acquireInfo, out IntPtr future);
|
||||
public delegate XrResult DelegateXrAcquirePersistedAnchorCollectionCompleteHTC(IntPtr future, out XrPersistedAnchorCollectionAcquireCompletionHTC completion);
|
||||
public delegate XrResult DelegateXrReleasePersistedAnchorCollectionHTC(IntPtr persistedAnchorCollection);
|
||||
public delegate XrResult DelegateXrPersistSpatialAnchorAsyncHTC(XrPersistedAnchorCollectionHTC persistedAnchorCollection, ref XrSpatialAnchorPersistInfoHTC persistInfo, out IntPtr future);
|
||||
public delegate XrResult DelegateXrPersistSpatialAnchorCompleteHTC(IntPtr future, out FutureWrapper.XrFutureCompletionEXT completion);
|
||||
public delegate XrResult DelegateXrUnpersistSpatialAnchorHTC(IntPtr persistedAnchorCollection, ref XrSpatialAnchorNameHTC persistedAnchorName);
|
||||
public delegate XrResult DelegateXrEnumeratePersistedAnchorNamesHTC( IntPtr persistedAnchorCollection, uint persistedAnchorNameCapacityInput, ref uint persistedAnchorNameCountOutput, [Out] XrSpatialAnchorNameHTC[] persistedAnchorNames);
|
||||
public delegate XrResult DelegateXrCreateSpatialAnchorFromPersistedAnchorAsyncHTC(XrSession session, ref XrSpatialAnchorFromPersistedAnchorCreateInfoHTC spatialAnchorCreateInfo, out IntPtr future);
|
||||
public delegate XrResult DelegateXrCreateSpatialAnchorFromPersistedAnchorCompleteHTC(IntPtr future, out XrSpatialAnchorFromPersistedAnchorCreateCompletionHTC completion);
|
||||
public delegate XrResult DelegateXrClearPersistedAnchorsHTC(IntPtr persistedAnchorCollection);
|
||||
public delegate XrResult DelegateXrGetPersistedAnchorPropertiesHTC(IntPtr persistedAnchorCollection, ref XrPersistedAnchorPropertiesGetInfoHTC getInfo);
|
||||
public delegate XrResult DelegateXrExportPersistedAnchorHTC(IntPtr persistedAnchorCollection, ref XrSpatialAnchorNameHTC persistedAnchorName, uint dataCapacityInput, ref uint dataCountOutput, [Out] byte[] data);
|
||||
public delegate XrResult DelegateXrImportPersistedAnchorHTC(IntPtr persistedAnchorCollection, uint dataCount, [In] byte[] data);
|
||||
public delegate XrResult DelegateXrGetPersistedAnchorNameFromBufferHTC(IntPtr persistedAnchorCollection, uint bufferCount, byte[] buffer, ref XrSpatialAnchorNameHTC name);
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnSystemChange(ulong xrSystem)
|
||||
{
|
||||
m_XrSystemId = xrSystem;
|
||||
Debug.Log("ViveAnchor OnSystemChange() " + m_XrSystemId);
|
||||
}
|
||||
DelegateXrCreateSpatialAnchorHTC XrCreateSpatialAnchorHTC;
|
||||
DelegateXrGetSpatialAnchorNameHTC XrGetSpatialAnchorNameHTC;
|
||||
DelegateXrAcquirePersistedAnchorCollectionAsyncHTC XrAcquirePersistedAnchorCollectionAsyncHTC;
|
||||
DelegateXrAcquirePersistedAnchorCollectionCompleteHTC XrAcquirePersistedAnchorCollectionCompleteHTC;
|
||||
DelegateXrReleasePersistedAnchorCollectionHTC XrReleasePersistedAnchorCollectionHTC;
|
||||
DelegateXrPersistSpatialAnchorAsyncHTC XrPersistSpatialAnchorAsyncHTC;
|
||||
DelegateXrPersistSpatialAnchorCompleteHTC XrPersistSpatialAnchorCompleteHTC;
|
||||
DelegateXrUnpersistSpatialAnchorHTC XrUnpersistSpatialAnchorHTC;
|
||||
DelegateXrEnumeratePersistedAnchorNamesHTC XrEnumeratePersistedAnchorNamesHTC;
|
||||
DelegateXrCreateSpatialAnchorFromPersistedAnchorAsyncHTC XrCreateSpatialAnchorFromPersistedAnchorAsyncHTC;
|
||||
DelegateXrCreateSpatialAnchorFromPersistedAnchorCompleteHTC XrCreateSpatialAnchorFromPersistedAnchorCompleteHTC;
|
||||
DelegateXrClearPersistedAnchorsHTC XrClearPersistedAnchorsHTC;
|
||||
DelegateXrGetPersistedAnchorPropertiesHTC XrGetPersistedAnchorPropertiesHTC;
|
||||
DelegateXrExportPersistedAnchorHTC XrExportPersistedAnchorHTC;
|
||||
DelegateXrImportPersistedAnchorHTC XrImportPersistedAnchorHTC;
|
||||
DelegateXrGetPersistedAnchorNameFromBufferHTC XrGetPersistedAnchorNameFromBufferHTC;
|
||||
|
||||
#endregion delegates and delegate instances
|
||||
|
||||
#endregion override functions
|
||||
#region override functions
|
||||
|
||||
private bool GetXrFunctionDelegates(XrInstance xrInstance)
|
||||
{
|
||||
Debug.Log("ViveAnchor GetXrFunctionDelegates() ");
|
||||
protected override IntPtr HookGetInstanceProcAddr(IntPtr func)
|
||||
{
|
||||
// For LocateSpace, need WaitFrame's predictedDisplayTime.
|
||||
ViveInterceptors.Instance.AddRequiredFunction("xrWaitFrame");
|
||||
return ViveInterceptors.Instance.HookGetInstanceProcAddr(func);
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
IntPtr funcPtr = IntPtr.Zero;
|
||||
OpenXRHelper.xrGetInstanceProcAddrDelegate GetAddr = CommonWrapper.Instance.GetInstanceProcAddr; // shorter name
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, xrInstance, "xrCreateSpatialAnchorHTC", out XrCreateSpatialAnchorHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, xrInstance, "xrGetSpatialAnchorNameHTC", out XrGetSpatialAnchorNameHTC);
|
||||
/// <inheritdoc />
|
||||
protected override bool OnInstanceCreate(ulong xrInstance)
|
||||
{
|
||||
#if FAKE_DATA
|
||||
Debug.LogError("ViveAnchor OnInstanceCreate() Use FakeData");
|
||||
useFakeData = true;
|
||||
#endif
|
||||
IsInited = false;
|
||||
bool ret = true;
|
||||
ret &= CommonWrapper.Instance.OnInstanceCreate(xrInstance, xrGetInstanceProcAddr);
|
||||
ret &= SpaceWrapper.Instance.OnInstanceCreate(xrInstance, xrGetInstanceProcAddr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
if (!ret)
|
||||
{
|
||||
Debug.LogError("ViveAnchor OnInstanceCreate() failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
#region functions of extension
|
||||
/// <summary>
|
||||
/// Helper function to get this feature' properties.
|
||||
/// See <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrGetSystemProperties">xrGetSystemProperties</see>
|
||||
/// </summary>
|
||||
public XrResult GetProperties(out XrSystemAnchorPropertiesHTC anchorProperties)
|
||||
{
|
||||
anchorProperties = new XrSystemAnchorPropertiesHTC();
|
||||
anchorProperties.type = XrStructureType.XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC;
|
||||
//Debug.Log("VIVEAnchor OnInstanceCreate() ");
|
||||
if (!OpenXRRuntime.IsExtensionEnabled("XR_HTC_anchor") && !useFakeData)
|
||||
{
|
||||
Debug.LogWarning("ViveAnchor OnInstanceCreate() XR_HTC_anchor is NOT enabled.");
|
||||
return false;
|
||||
}
|
||||
|
||||
IsInited = GetXrFunctionDelegates(xrInstance);
|
||||
|
||||
if (!IsInited)
|
||||
{
|
||||
Debug.LogError("ViveAnchor OnInstanceCreate() failed to get function delegates.");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_XrInstance = xrInstance;
|
||||
|
||||
bool hasFuture = FutureWrapper.Instance.OnInstanceCreate(xrInstance, xrGetInstanceProcAddr);
|
||||
// No error log because future will print.
|
||||
#if FAKE_DATA
|
||||
hasFuture = true;
|
||||
#endif
|
||||
IsPAInited = false;
|
||||
bool hasPersistedAnchor = false;
|
||||
do
|
||||
{
|
||||
if (!hasFuture)
|
||||
{
|
||||
Debug.LogWarning("ViveAnchor OnInstanceCreate() XR_HTC_anchor_persistence is NOT enabled because no XR_EXT_future.");
|
||||
hasPersistedAnchor = false;
|
||||
break;
|
||||
}
|
||||
|
||||
hasPersistedAnchor = enablePersistedAnchor && OpenXRRuntime.IsExtensionEnabled("XR_HTC_anchor_persistence");
|
||||
#if FAKE_DATA
|
||||
hasPersistedAnchor = enablePersistedAnchor;
|
||||
#endif
|
||||
} while(false);
|
||||
|
||||
//Debug.Log("OnInstanceCreate() " + m_XrInstance);
|
||||
if (hasPersistedAnchor)
|
||||
IsPAInited = GetXrFunctionDelegatesPersistance(xrInstance);
|
||||
if (!IsPAInited)
|
||||
Debug.LogWarning("ViveAnchor OnInstanceCreate() XR_HTC_anchor_persistence is NOT enabled.");
|
||||
|
||||
return IsInited;
|
||||
}
|
||||
|
||||
protected override void OnInstanceDestroy(ulong xrInstance)
|
||||
{
|
||||
m_XrInstance = 0;
|
||||
|
||||
IsInited = false;
|
||||
IsPAInited = false;
|
||||
|
||||
CommonWrapper.Instance.OnInstanceDestroy();
|
||||
SpaceWrapper.Instance.OnInstanceDestroy();
|
||||
FutureWrapper.Instance.OnInstanceDestroy();
|
||||
Debug.Log("ViveAnchor: OnInstanceDestroy()");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnSessionCreate(ulong xrSession)
|
||||
{
|
||||
//Debug.Log("ViveAnchor OnSessionCreate() ");
|
||||
session = xrSession;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnSessionDestroy(ulong xrSession)
|
||||
{
|
||||
//Debug.Log("ViveAnchor OnSessionDestroy() ");
|
||||
session = 0;
|
||||
}
|
||||
|
||||
// XXX Every millisecond the AppSpace switched from one space to another space. I don't know what is going on.
|
||||
//private ulong appSpace;
|
||||
//protected override void OnAppSpaceChange(ulong space)
|
||||
//{
|
||||
// //Debug.Log($"VIVEAnchor OnAppSpaceChange({appSpace} -> {space})");
|
||||
// appSpace = space;
|
||||
//}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnSystemChange(ulong xrSystem)
|
||||
{
|
||||
m_XrSystemId = xrSystem;
|
||||
//Debug.Log("ViveAnchor OnSystemChange() " + m_XrSystemId);
|
||||
}
|
||||
|
||||
#endregion override functions
|
||||
|
||||
private bool GetXrFunctionDelegates(XrInstance inst)
|
||||
{
|
||||
Debug.Log("ViveAnchor GetXrFunctionDelegates() ");
|
||||
|
||||
bool ret = true;
|
||||
OpenXRHelper.xrGetInstanceProcAddrDelegate GetAddr = CommonWrapper.Instance.GetInstanceProcAddr; // shorter name
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrCreateSpatialAnchorHTC", out XrCreateSpatialAnchorHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrGetSpatialAnchorNameHTC", out XrGetSpatialAnchorNameHTC);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool GetXrFunctionDelegatesPersistance(XrInstance inst)
|
||||
{
|
||||
Debug.Log("ViveAnchor GetXrFunctionDelegatesPersistance() ");
|
||||
bool ret = true;
|
||||
OpenXRHelper.xrGetInstanceProcAddrDelegate GetAddr = CommonWrapper.Instance.GetInstanceProcAddr; // shorter name
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrAcquirePersistedAnchorCollectionAsyncHTC", out XrAcquirePersistedAnchorCollectionAsyncHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrAcquirePersistedAnchorCollectionCompleteHTC", out XrAcquirePersistedAnchorCollectionCompleteHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrReleasePersistedAnchorCollectionHTC", out XrReleasePersistedAnchorCollectionHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrPersistSpatialAnchorAsyncHTC", out XrPersistSpatialAnchorAsyncHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrPersistSpatialAnchorCompleteHTC", out XrPersistSpatialAnchorCompleteHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrUnpersistSpatialAnchorHTC", out XrUnpersistSpatialAnchorHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrEnumeratePersistedAnchorNamesHTC", out XrEnumeratePersistedAnchorNamesHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrCreateSpatialAnchorFromPersistedAnchorAsyncHTC", out XrCreateSpatialAnchorFromPersistedAnchorAsyncHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrCreateSpatialAnchorFromPersistedAnchorCompleteHTC", out XrCreateSpatialAnchorFromPersistedAnchorCompleteHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrClearPersistedAnchorsHTC", out XrClearPersistedAnchorsHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrGetPersistedAnchorPropertiesHTC", out XrGetPersistedAnchorPropertiesHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrExportPersistedAnchorHTC", out XrExportPersistedAnchorHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrImportPersistedAnchorHTC", out XrImportPersistedAnchorHTC);
|
||||
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, inst, "xrGetPersistedAnchorNameFromBufferHTC", out XrGetPersistedAnchorNameFromBufferHTC);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#region functions of extension
|
||||
/// <summary>
|
||||
/// Helper function to get this feature's properties.
|
||||
/// See <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrGetSystemProperties">xrGetSystemProperties</see>
|
||||
/// </summary>
|
||||
/// <param name="anchorProperties">Output parameter to hold anchor properties.</param>
|
||||
/// <returns>XrResult indicating success or failure.</returns>
|
||||
public XrResult GetProperties(out XrSystemAnchorPropertiesHTC anchorProperties)
|
||||
{
|
||||
anchorProperties = new XrSystemAnchorPropertiesHTC();
|
||||
anchorProperties.type = XrStructureType.XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC;
|
||||
|
||||
#if FAKE_DATA
|
||||
if (Application.isEditor)
|
||||
{
|
||||
anchorProperties.type = XrStructureType.XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC;
|
||||
anchorProperties.supportsAnchor = true;
|
||||
return XrResult.XR_SUCCESS;
|
||||
}
|
||||
if (Application.isEditor)
|
||||
{
|
||||
anchorProperties.type = XrStructureType.XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC;
|
||||
anchorProperties.supportsAnchor = true;
|
||||
return XrResult.XR_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
return CommonWrapper.Instance.GetProperties(m_XrInstance, m_XrSystemId, ref anchorProperties);
|
||||
}
|
||||
return CommonWrapper.Instance.GetProperties(m_XrInstance, m_XrSystemId, ref anchorProperties);
|
||||
}
|
||||
|
||||
public XrResult CreateSpatialAnchor(XrSpatialAnchorCreateInfoHTC createInfo, out XrSpace anchor)
|
||||
{
|
||||
anchor = default;
|
||||
#if FAKE_DATA
|
||||
if (Application.isEditor)
|
||||
return XrResult.XR_SUCCESS;
|
||||
#endif
|
||||
var ret = XrCreateSpatialAnchorHTC(session, ref createInfo, ref anchor);
|
||||
Debug.Log("ViveAnchor CreateSpatialAnchor() r=" + ret + ", a=" + anchor + ", bs=" + createInfo.space +
|
||||
", pos=(" + createInfo.poseInSpace.position.x + "," + createInfo.poseInSpace.position.y + "," + createInfo.poseInSpace.position.z +
|
||||
"), rot=(" + createInfo.poseInSpace.orientation.x + "," + createInfo.poseInSpace.orientation.y + "," + createInfo.poseInSpace.orientation.z + "," + createInfo.poseInSpace.orientation.w +
|
||||
"), n=" + createInfo.name.name);
|
||||
return ret;
|
||||
}
|
||||
/// <summary>
|
||||
/// The CreateSpatialAnchor function creates a spatial anchor with specified base space and pose in the space.
|
||||
/// The anchor is represented by an XrSpace and its pose can be tracked via xrLocateSpace.
|
||||
/// Once the anchor is no longer needed, call xrDestroySpace to erase the anchor.
|
||||
/// </summary>
|
||||
/// <param name="createInfo">Information required to create the spatial anchor.</param>
|
||||
/// <param name="anchor">Output parameter to hold the created anchor.</param>
|
||||
/// <returns>XrResult indicating success or failure.</returns>
|
||||
public XrResult CreateSpatialAnchor(XrSpatialAnchorCreateInfoHTC createInfo, out XrSpace anchor)
|
||||
{
|
||||
anchor = default;
|
||||
if (!IsInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
if (session == 0)
|
||||
return XrResult.XR_ERROR_SESSION_LOST;
|
||||
|
||||
public XrResult GetSpatialAnchorName(XrSpace anchor, out XrSpatialAnchorNameHTC name)
|
||||
{
|
||||
name = default;
|
||||
#if FAKE_DATA
|
||||
if (Application.isEditor)
|
||||
{
|
||||
name.name = "fake anchor";
|
||||
return XrResult.XR_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
return XrGetSpatialAnchorNameHTC(anchor, ref name);
|
||||
}
|
||||
var ret = XrCreateSpatialAnchorHTC(session, ref createInfo, ref anchor);
|
||||
//Debug.Log("ViveAnchor CreateSpatialAnchor() r=" + ret + ", a=" + anchor + ", bs=" + createInfo.space +
|
||||
// ", pos=(" + createInfo.poseInSpace.position.x + "," + createInfo.poseInSpace.position.y + "," + createInfo.poseInSpace.position.z +
|
||||
// "), rot=(" + createInfo.poseInSpace.orientation.x + "," + createInfo.poseInSpace.orientation.y + "," + createInfo.poseInSpace.orientation.z + "," + createInfo.poseInSpace.orientation.w +
|
||||
// "), n=" + createInfo.name.name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// The GetSpatialAnchorName function retrieves the name of the spatial anchor.
|
||||
/// </summary>
|
||||
/// <param name="anchor">The XrSpace representing the anchor.</param>
|
||||
/// <param name="name">Output parameter to hold the name of the anchor.</param>
|
||||
/// <returns>XrResult indicating success or failure.</returns>
|
||||
public XrResult GetSpatialAnchorName(XrSpace anchor, out XrSpatialAnchorNameHTC name)
|
||||
{
|
||||
name = new XrSpatialAnchorNameHTC();
|
||||
if (!IsInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
return XrGetSpatialAnchorNameHTC(anchor, ref name);
|
||||
}
|
||||
|
||||
#region tools for user
|
||||
/// <summary>
|
||||
/// If the extension is supported and enabled, return true.
|
||||
/// </summary>
|
||||
/// <returns>True if persisted anchor extension is supported, false otherwise.</returns>
|
||||
public bool IsPersistedAnchorSupported()
|
||||
{
|
||||
return IsPAInited;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// According to XRInputSubsystem's tracking origin mode, return the corresponding XrSpace.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public XrSpace GetTrackingSpace()
|
||||
{
|
||||
var s = GetCurrentAppSpace();
|
||||
Debug.Log("ViveAnchor GetTrackingSpace() s=" + s);
|
||||
return s;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a persisted anchor collection. This collection can be used to persist spatial anchors across sessions.
|
||||
/// Many persisted anchor APIs need a persisted anchor collection to operate.
|
||||
/// </summary>
|
||||
/// <param name="future">Output the async future handle. Check the future to get the PersitedAnchorCollection handle.</param>
|
||||
/// <returns>XrResult indicating success or failure.</returns>
|
||||
public XrResult AcquirePersistedAnchorCollectionAsync(out IntPtr future)
|
||||
{
|
||||
future = IntPtr.Zero;
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
if (session == 0)
|
||||
return XrResult.XR_ERROR_SESSION_LOST;
|
||||
|
||||
XrPersistedAnchorCollectionAcquireInfoHTC acquireInfo = new XrPersistedAnchorCollectionAcquireInfoHTC
|
||||
{
|
||||
type = XrStructureType.XR_TYPE_PERSISTED_ANCHOR_COLLECTION_ACQUIRE_INFO_HTC,
|
||||
next = IntPtr.Zero,
|
||||
};
|
||||
|
||||
return XrAcquirePersistedAnchorCollectionAsyncHTC(session, ref acquireInfo, out future);
|
||||
}
|
||||
|
||||
public XrResult AcquirePersistedAnchorCollectionComplete(IntPtr future, out XrPersistedAnchorCollectionAcquireCompletionHTC completion)
|
||||
{
|
||||
completion = new XrPersistedAnchorCollectionAcquireCompletionHTC();
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
|
||||
return XrAcquirePersistedAnchorCollectionCompleteHTC(future, out completion);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Destroys the persisted anchor collection.
|
||||
/// </summary>
|
||||
/// <param name="persistedAnchorCollection">The persisted anchor collection to be destroyed.</param>
|
||||
/// <returns>XrResult indicating success or failure.</returns>
|
||||
public XrResult ReleasePersistedAnchorCollection(IntPtr persistedAnchorCollection)
|
||||
{
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
|
||||
return XrReleasePersistedAnchorCollectionHTC(persistedAnchorCollection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Persists a spatial anchor with the given name. The name should be unique.
|
||||
/// </summary>
|
||||
/// <param name="persistedAnchorCollection">The persisted anchor collection to operate.</param>
|
||||
/// <param name="anchor">The spatial anchor to be persisted.</param>
|
||||
/// <param name="name">The name of the persisted anchor.</param>
|
||||
/// <returns>XrResult indicating success or failure.</returns>
|
||||
public XrResult PersistSpatialAnchorAsync(IntPtr persistedAnchorCollection, XrSpace anchor, XrSpatialAnchorNameHTC name, out IntPtr future)
|
||||
{
|
||||
future = IntPtr.Zero;
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
|
||||
XrSpatialAnchorPersistInfoHTC persistInfo = new XrSpatialAnchorPersistInfoHTC
|
||||
{
|
||||
type = XrStructureType.XR_TYPE_SPATIAL_ANCHOR_PERSIST_INFO_HTC,
|
||||
anchor = anchor,
|
||||
persistedAnchorName = name
|
||||
};
|
||||
return XrPersistSpatialAnchorAsyncHTC(persistedAnchorCollection, ref persistInfo, out future);
|
||||
}
|
||||
|
||||
public XrResult PersistSpatialAnchorComplete(IntPtr future, out FutureWrapper.XrFutureCompletionEXT completion)
|
||||
{
|
||||
completion = new FutureWrapper.XrFutureCompletionEXT() {
|
||||
type = XrStructureType.XR_TYPE_FUTURE_COMPLETION_EXT,
|
||||
next = IntPtr.Zero,
|
||||
futureResult = XrResult.XR_SUCCESS
|
||||
};
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
|
||||
return XrPersistSpatialAnchorCompleteHTC(future, out completion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpersists the anchor with the given name.
|
||||
/// </summary>
|
||||
/// <param name="persistedAnchorCollection">The persisted anchor collection to operate.</param>
|
||||
/// <param name="name">The name of the anchor to be unpersisted.</param>
|
||||
/// <returns>XrResult indicating success or failure.</returns>
|
||||
public XrResult UnpersistSpatialAnchor(IntPtr persistedAnchorCollection, XrSpatialAnchorNameHTC name)
|
||||
{
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
|
||||
return XrUnpersistSpatialAnchorHTC(persistedAnchorCollection, ref name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates all persisted anchor names.
|
||||
/// </summary>
|
||||
/// <param name="persistedAnchorCollection">The persisted anchor collection to operate.</param>
|
||||
/// <param name="persistedAnchorNameCapacityInput">The capacity of the input buffer.</param>
|
||||
/// <param name="persistedAnchorNameCountOutput">Output parameter to hold the count of persisted anchor names.</param>
|
||||
/// <param name="persistedAnchorNames">Output parameter to hold the names of persisted anchors.</param>
|
||||
/// <returns>XrResult indicating success or failure.</returns>
|
||||
public XrResult EnumeratePersistedAnchorNames(IntPtr persistedAnchorCollection, uint persistedAnchorNameCapacityInput,
|
||||
ref uint persistedAnchorNameCountOutput, ref XrSpatialAnchorNameHTC[] persistedAnchorNames)
|
||||
{
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
|
||||
return XrEnumeratePersistedAnchorNamesHTC(persistedAnchorCollection, persistedAnchorNameCapacityInput, ref persistedAnchorNameCountOutput, persistedAnchorNames);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a spatial anchor from a persisted anchor.
|
||||
/// </summary>
|
||||
/// <param name="spatialAnchorCreateInfo">Information required to create the spatial anchor from persisted anchor.</param>
|
||||
/// <param name="anchor">Output parameter to hold the created spatial anchor.</param>
|
||||
/// <returns>XrResult indicating success or failure.</returns>
|
||||
public XrResult CreateSpatialAnchorFromPersistedAnchorAsync(XrSpatialAnchorFromPersistedAnchorCreateInfoHTC spatialAnchorCreateInfo, out IntPtr future)
|
||||
{
|
||||
future = IntPtr.Zero;
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
if (session == 0)
|
||||
return XrResult.XR_ERROR_SESSION_LOST;
|
||||
return XrCreateSpatialAnchorFromPersistedAnchorAsyncHTC(session, ref spatialAnchorCreateInfo, out future);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When the future is ready, call this function to get the result.
|
||||
/// </summary>
|
||||
/// <param name="future"></param>
|
||||
/// <param name="completion"></param>
|
||||
/// <returns></returns>
|
||||
public XrResult CreateSpatialAnchorFromPersistedAnchorComplete(IntPtr future, out XrSpatialAnchorFromPersistedAnchorCreateCompletionHTC completion)
|
||||
{
|
||||
completion = new XrSpatialAnchorFromPersistedAnchorCreateCompletionHTC()
|
||||
{
|
||||
type = XrStructureType.XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_COMPLETION_HTC,
|
||||
next = IntPtr.Zero,
|
||||
futureResult = XrResult.XR_SUCCESS,
|
||||
anchor = 0
|
||||
};
|
||||
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
return XrCreateSpatialAnchorFromPersistedAnchorCompleteHTC(future, out completion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all persisted anchors.
|
||||
/// </summary>
|
||||
/// <param name="persistedAnchorCollection">The persisted anchor collection to operate.</param>
|
||||
/// <returns>XrResult indicating success or failure.</returns>
|
||||
public XrResult ClearPersistedAnchors(IntPtr persistedAnchorCollection)
|
||||
{
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
return XrClearPersistedAnchorsHTC(persistedAnchorCollection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the properties of the persisted anchor.
|
||||
/// </summary>
|
||||
/// <param name="persistedAnchorCollection">The persisted anchor collection to operate.</param>
|
||||
/// <param name="getInfo">Output parameter to hold the properties of the persisted anchor.</param>
|
||||
/// <returns>XrResult indicating success or failure.</returns>
|
||||
public XrResult GetPersistedAnchorProperties(IntPtr persistedAnchorCollection, out XrPersistedAnchorPropertiesGetInfoHTC getInfo)
|
||||
{
|
||||
getInfo = new XrPersistedAnchorPropertiesGetInfoHTC
|
||||
{
|
||||
type = XrStructureType.XR_TYPE_PERSISTED_ANCHOR_PROPERTIES_GET_INFO_HTC
|
||||
};
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
return XrGetPersistedAnchorPropertiesHTC(persistedAnchorCollection, ref getInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports the persisted anchor to a buffer. The buffer can be used to import the anchor later or save to a file.
|
||||
/// </summary>
|
||||
/// <param name="persistedAnchorCollection">The persisted anchor collection to operate.</param>
|
||||
/// <param name="persistedAnchorName">The name of the persisted anchor to be exported.</param>
|
||||
/// <param name="data">Output parameter to hold the buffer containing the exported anchor.</param>
|
||||
/// <returns>XrResult indicating success or failure.</returns>
|
||||
public XrResult ExportPersistedAnchor(IntPtr persistedAnchorCollection, XrSpatialAnchorNameHTC persistedAnchorName, out byte[] data)
|
||||
{
|
||||
data = null;
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
uint dataCountOutput = 0;
|
||||
uint dataCapacityInput = 0;
|
||||
XrResult ret = XrExportPersistedAnchorHTC(persistedAnchorCollection, ref persistedAnchorName, dataCapacityInput, ref dataCountOutput, null);
|
||||
if (ret != XrResult.XR_SUCCESS)
|
||||
{
|
||||
Debug.LogError("ExportPersistedAnchor failed to get data size. ret=" + ret);
|
||||
data = null;
|
||||
return ret;
|
||||
}
|
||||
|
||||
dataCapacityInput = dataCountOutput;
|
||||
data = new byte[dataCountOutput];
|
||||
ret = XrExportPersistedAnchorHTC(persistedAnchorCollection, ref persistedAnchorName, dataCapacityInput, ref dataCountOutput, data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imports the persisted anchor from a buffer. The buffer should be created by ExportPersistedAnchor.
|
||||
/// </summary>
|
||||
/// <param name="persistedAnchorCollection">The persisted anchor collection to operate.</param>
|
||||
/// <param name="data">The buffer containing the persisted anchor data.</param>
|
||||
/// <returns>XrResult indicating success or failure.</returns>
|
||||
public XrResult ImportPersistedAnchor(IntPtr persistedAnchorCollection, byte[] data)
|
||||
{
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
|
||||
return XrImportPersistedAnchorHTC(persistedAnchorCollection, (uint)data.Length, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the persisted anchor from a buffer. The buffer should be created by ExportPersistedAnchor.
|
||||
/// </summary>
|
||||
/// <param name="persistedAnchorCollection"></param>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public XrResult GetPersistedAnchorNameFromBuffer(IntPtr persistedAnchorCollection, byte[] buffer, out XrSpatialAnchorNameHTC name)
|
||||
{
|
||||
name = new XrSpatialAnchorNameHTC();
|
||||
if (!IsPAInited)
|
||||
return XrResult.XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
|
||||
if (buffer == null)
|
||||
return XrResult.XR_ERROR_VALIDATION_FAILURE;
|
||||
|
||||
return XrGetPersistedAnchorNameFromBufferHTC(persistedAnchorCollection, (uint)buffer.Length, buffer, ref name);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region tools for user
|
||||
|
||||
/// <summary>
|
||||
/// According to XRInputSubsystem's tracking origin mode, return the corresponding XrSpace.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public XrSpace GetTrackingSpace()
|
||||
{
|
||||
var s = GetCurrentAppSpace();
|
||||
//Debug.Log("ViveAnchor GetTrackingSpace() s=" + s);
|
||||
return s;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user