October3d55/Matain/ViveOpenXR/Source/ViveOpenXRAnchor/Private/ViveOpenXRAnchorModuleAR.cpp

407 lines
14 KiB
C++
Raw Normal View History

2025-03-10 09:43:27 +08:00
// Copyright HTC Corporation. All Rights Reserved.
#include "ViveOpenXRAnchorModule.h"
#include "OpenXRCore.h"
#include "Modules/ModuleManager.h"
#include "ARBlueprintLibrary.h"
#include "IOpenXRARModule.h"
#include "ARPin.h"
#include "ViveOpenXRAnchorAsyncTask.h"
IOpenXRCustomAnchorSupport* FViveOpenXRAnchor::GetCustomAnchorSupport()
{
//UE_LOG(ViveOXRAnchor, Log, TEXT("GetCustomAnchorSupport()"));
return this;
}
void FViveOpenXRAnchor::OnStartARSession(class UARSessionConfig* SessionConfig) {
UE_LOG(ViveOXRAnchor, Log, TEXT("OnStartARSession()"));
timeSinceARStarted = FPlatformTime::Seconds();
isARRequestedPersistedAnchorCollection = true;
CheckPersistedAnchorCollectionAR();
}
void FViveOpenXRAnchor::OnPauseARSession() {
}
void FViveOpenXRAnchor::OnStopARSession() {
UE_LOG(ViveOXRAnchor, Log, TEXT("OnStopARSession()"));
isARRequestedPersistedAnchorCollection = false;
if (paCollectionAR != nullptr) {
ReleasePersistedAnchorCollection(paCollectionAR);
paCollectionAR = nullptr;
}
timeSinceARStarted = 0;
}
void FViveOpenXRAnchor::CheckPersistedAnchorCollectionAR() {
if (paCollectionAR != nullptr)
return;
if (!isAnchorPersistenceSupported) {
UE_LOG(ViveOXRAnchor, Log, TEXT("CheckPersistedAnchorCollectionAR() Anchor persistence is not supported."));
return;
}
if (paCollectionAR == nullptr && isARRequestedPersistedAnchorCollection) {
if (pacFuture == nullptr) {
auto ret = AcquirePersistedAnchorCollectionAsync(&pacFuture);
if (XR_SUCCEEDED(ret)) {
UE_LOG(ViveOXRAnchor, Log, TEXT("CheckPersistedAnchorCollectionAR() Persisted anchor collection is acquiring."));
} else {
pacFuture = nullptr;
isARRequestedPersistedAnchorCollection = false;
UE_LOG(ViveOXRAnchor, Error, TEXT("CheckPersistedAnchorCollectionAR() Persisted anchor collection creation is failed."));
}
} else {
bool isReady = false;
auto futureMod = FViveOpenXRFuture::Instance();
if (futureMod == nullptr) return;
auto ret = futureMod->PollFuture(pacFuture, isReady);
if (XR_FAILED(ret)) {
pacFuture = nullptr;
isARRequestedPersistedAnchorCollection = false;
return;
}
if (isReady)
{
XrPersistedAnchorCollectionAcquireCompletionHTC completion;
ret = AcquirePersistedAnchorCollectionComplete(pacFuture, &completion);
if (XR_SUCCEEDED(completion.futureResult)) {
UE_LOG(ViveOXRAnchor, Log, TEXT("CheckPersistedAnchorCollectionAR() PAC=%p is acquired."), completion.persistedAnchorCollection);
paCollectionAR = completion.persistedAnchorCollection;
}
else
isARRequestedPersistedAnchorCollection = false;
pacFuture = nullptr;
}
}
}
}
bool FViveOpenXRAnchor::OnPinComponent(UARPin* Pin, XrSession InSession, XrSpace TrackingSpace, XrTime DisplayTime, float worldToMeterScale)
{
UE_LOG(ViveOXRAnchor, Log, TEXT("OnPinComponent()"));
auto t = Pin->GetLocalToTrackingTransform();
auto loc = t.GetLocation();
auto rot = t.GetRotation();
auto debugName = Pin->GetDebugName().ToString();
if (debugName.IsEmpty())
debugName = "NoName";
// XXX We cannot create a unique anchor name and pass the created name to upper level system. Therefore its user's responsiblity to create unique name.
// Create unique persisted anchor name
// auto name = GenerateAnchorName(debugName);
XrSpatialAnchorCreateInfoHTC createInfo = MakeCreateInfo(loc, rot, TrackingSpace, debugName, worldToMeterScale);
XrSpace anchor = 0;
if (!CreateSpatialAnchor(&createInfo, &anchor)) return false;
Pin->SetNativeResource(anchor);
return true;
}
void FViveOpenXRAnchor::OnRemovePin(UARPin* Pin)
{
XrSpace anchor = (XrSpace)Pin->GetNativeResource();
if (xrDestroySpace == nullptr) return;
xrDestroySpace(anchor);
Pin->SetPinnedComponent(nullptr);
Pin->SetNativeResource(nullptr);
}
void FViveOpenXRAnchor::OnUpdatePin(UARPin* Pin, XrSession InSession, XrSpace TrackingSpace, XrTime DisplayTime, float worldToMeterScale)
{
FRotator rotation;
FVector translation;
if (!LocateAnchor((XrSpace)Pin->GetNativeResource(), rotation, translation))
return;
Pin->OnTransformUpdated(FTransform(rotation, translation, FVector(1, 1, 1)));
}
bool FViveOpenXRAnchor::IsLocalPinSaveSupported() const
{
//UE_LOG(ViveOXRAnchor, Log, TEXT("IsLocalPinSaveSupported()=%d"), isARRequestedPersistedAnchorCollection && isAnchorPersistenceSupported);
return isARRequestedPersistedAnchorCollection && isAnchorPersistenceSupported;
}
bool FViveOpenXRAnchor::ArePinsReadyToLoad()
{
// If AR session is not started, we don't need to check persisted anchor collection.
if (!IsLocalPinSaveSupported()) return false;
CheckPersistedAnchorCollectionAR();
if (paCollectionAR == nullptr) {
UE_LOG(ViveOXRAnchor, Log, TEXT("ArePinsReadyToLoad() = false"));
return false;
}
return true;
}
void FViveOpenXRAnchor::LoadARPins(XrSession InSession, TFunction<UARPin* (FName)> OnCreatePin)
{
UE_LOG(ViveOXRAnchor, Log, TEXT("LoadARPins()"));
if (!IsLocalPinSaveSupported()) return;
CheckPersistedAnchorCollectionAR();
if (paCollectionAR == nullptr) {
UE_LOG(ViveOXRAnchor, Error, TEXT("SaveARPin() Anchor persistence is not exist. Check IsLocalPinSaveSupported first."));
return;
}
XrResult ret = XR_SUCCESS;
uint32_t count = 0;
TArray<XrSpatialAnchorNameHTC> AnchorNames;
// enumerate persisted anchors
xrEnumeratePersistedAnchorNamesHTC(paCollectionAR, 0, &count, nullptr);
if (count != 0) {
AnchorNames.SetNum(count);
xrEnumeratePersistedAnchorNamesHTC(paCollectionAR, count, &count, AnchorNames.GetData());
}
else
{
UE_LOG(ViveOXRAnchor, Log, TEXT("LoadARPins() No Anchor name found: %d."), count);
}
UE_LOG(ViveOXRAnchor, Log, TEXT("LoadARPins() EnumeratePersistedAnchorCount: %d."), count);
int created = 0;
TArray<XrFutureEXT> list;
// Get all PersistedAnchor from CollectionHTC
for (auto name : AnchorNames)
{
FString paName = ToFString(name);
UE_LOG(ViveOXRAnchor, Log, TEXT("LoadARPins() EnumeratePersistedAnchorName: %s."), *paName);
FString aName = paName;
if (aName.EndsWith(TEXT("_PA")))
{
aName = aName.Replace(TEXT("_PA"), TEXT(""));
}
UE_LOG(LogTemp, Log, TEXT("LoadARPins() Make spatial anchor: %s from persisted anchor: %s"), *aName, *paName);
XrSpatialAnchorFromPersistedAnchorCreateInfoHTC createInfo =
MakeSpatialAnchorFromPersistedAnchorCreateInfo(paCollectionAR, paName, aName);
XrFutureEXT future;
ret = CreateSpatialAnchorFromPersistedAnchorAsync(&createInfo, &future);
if (ret == XR_SUCCESS) {
list.Add(future);
}
}
while (!list.IsEmpty()) {
TArray<XrFutureEXT> nextList;
int N = list.Num();
for (int i = 0; i < N; i++)
{
auto future = list[i];
if (future == nullptr) continue;
bool isReady = false;
auto futureMod = FViveOpenXRFuture::Instance();
if (futureMod == nullptr) return;
ret = futureMod->PollFuture(future, isReady);
if (XR_FAILED(ret))
{
UE_LOG(ViveOXRAnchor, Error, TEXT("LoadARPins() PollFuture failed with result %d."), ret);
continue;
}
if (!isReady)
{
nextList.Add(future);
continue;
}
XrSpatialAnchorFromPersistedAnchorCreateCompletionHTC completion = {
.type = XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_COMPLETION_HTC,
.next = nullptr,
.futureResult = XR_SUCCESS,
.anchor = 0
};
XrResult completeResult = CreateSpatialAnchorFromPersistedAnchorComplete(future, &completion);
if (XR_FAILED(completeResult) || XR_FAILED(completion.futureResult))
{
UE_LOG(ViveOXRAnchor, Error, TEXT("Failed to create spatial anchor from persisted anchor: completeResult=%d futureResult=%d"), completeResult, completion.futureResult);
}
else
{
UE_LOG(ViveOXRAnchor, Log, TEXT("CreateSpatialAnchorFromPersistedAnchor is success. anchor=%p. Invoke OnCreatePin."), completion.anchor);
auto anchor = completion.anchor;
XrSpatialAnchorNameHTC anchorName;
FString aName;
if (GetSpatialAnchorName(anchor, &anchorName))
aName = ToFString(anchorName);
// Set user defined name to ARPin
UARPin* pin = OnCreatePin(FName(aName));
if (pin != nullptr) {
pin->SetNativeResource(anchor);
created++;
}
}
}
list = nextList;
FPlatformProcess::Sleep(0);
}
UE_LOG(ViveOXRAnchor, Log, TEXT("LoadARPins() Created %d ARPin(s)."), created);
}
bool FViveOpenXRAnchor::SaveARPin(XrSession InSession, FName InName, UARPin* InPin)
{
UE_LOG(ViveOXRAnchor, Log, TEXT("SaveARPin()"));
if (!IsLocalPinSaveSupported()) return false;
CheckPersistedAnchorCollectionAR();
if (paCollectionAR == nullptr) {
UE_LOG(ViveOXRAnchor, Error, TEXT("SaveARPin() Anchor persistence is not exist. Check IsLocalPinSaveSupported first."));
return false;
}
if (InPin == nullptr || InPin->GetNativeResource() == nullptr) {
UE_LOG(ViveOXRAnchor, Error, TEXT("SaveARPin() Invalid ARPin."));
return false;
}
FString aName = InName.ToString();
FString paName;
if (!aName.EndsWith(TEXT("_PA")))
{
paName = aName + TEXT("_PA");
}
UE_LOG(ViveOXRAnchor, Log, TEXT("SaveARPin() aName: %s"), *aName);
UE_LOG(ViveOXRAnchor, Log, TEXT("SaveARPin() paName: %s"), *paName);
// XXX We cannot create a unique anchor name and pass the created name to upper level system. Therefore its user's responsiblity to create unique name.
// Create unique persisted anchor name
// name = GenerateAnchorName(name);
XrSpatialAnchorPersistInfoHTC info = {
XR_TYPE_SPATIAL_ANCHOR_PERSIST_INFO_HTC,
nullptr,
(XrSpace)InPin->GetNativeResource(),
FromFString(paName)
};
XrFutureEXT future;
auto ret = PersistSpatialAnchorAsync(paCollectionAR, &info, &future);
while (true) {
bool isReady = false;
auto futureMod = FViveOpenXRFuture::Instance();
if (futureMod == nullptr) return false;
ret = futureMod->PollFuture(future, isReady);
if (XR_FAILED(ret))
{
UE_LOG(ViveOXRAnchor, Error, TEXT("SaveARPin() PersistSpatialAnchor failed when pollFuture with result %d."), ret);
break;
}
else if (isReady)
{
XrFutureCompletionEXT completion;
ret = PersistSpatialAnchorComplete(future, &completion);
if (XR_FAILED(ret)) {
UE_LOG(ViveOXRAnchor, Error, TEXT("SaveARPin() PersistSpatialAnchor failed when complete with result %d."), ret);
return false;
}
if (XR_FAILED(completion.futureResult)) {
UE_LOG(ViveOXRAnchor, Error, TEXT("SaveARPin() PersistSpatialAnchor failed with result %d."), completion.futureResult);
return false;
}
UE_LOG(ViveOXRAnchor, Log, TEXT("SaveARPin() PersistSpatialAnchor success."));
return true;
}
}
return false;
}
void FViveOpenXRAnchor::RemoveSavedARPin(XrSession InSession, FName InName)
{
UE_LOG(ViveOXRAnchor, Log, TEXT("RemoveSavedARPin()"));
if (!IsLocalPinSaveSupported()) return;
CheckPersistedAnchorCollectionAR();
if (paCollectionAR == nullptr) {
// If supported, when ARSession started, it should be created. Developer Should check IsLocalPinSaveSupported first.
UE_LOG(ViveOXRAnchor, Error, TEXT("SaveARPin() Anchor persistence is not exist. Check IsLocalPinSaveSupported first."));
return;
}
// Add ARPin marker
FString aName = InName.ToString();
FString paName = aName;
if (!paName.EndsWith(TEXT("_PA")))
{
paName += TEXT("_PA");
}
UE_LOG(ViveOXRAnchor, Log, TEXT("Remove : %s from Local"), *aName);
UE_LOG(ViveOXRAnchor, Log, TEXT("Remove : %s from Collection"), *paName);
XrSpatialAnchorNameHTC xrName = FromFString(paName);
// Remove SpatialAnchor from collectionHTC
auto ret = UnpersistSpatialAnchor(paCollectionAR, &xrName);
if (ret != XR_SUCCESS) {
UE_LOG(ViveOXRAnchor, Error, TEXT("RemoveSavedARPin() UnpersistSpatialAnchor failed with result %d."), ret);
}
UE_LOG(ViveOXRAnchor, Log, TEXT("Check collection removed"));
uint32_t nameCount = 0;
XrSpatialAnchorNameHTC* xrNames = new XrSpatialAnchorNameHTC[nameCount];
FMemory::Memset(xrNames, 0, sizeof(XrSpatialAnchorNameHTC) * nameCount);
XrResult result = EnumeratePersistedAnchorNames((XrPersistedAnchorCollectionHTC)paCollectionAR, nameCount, &nameCount, xrNames);
if (XR_FAILED(result))
{
UE_LOG(ViveOXRAnchor, Error, TEXT("Failed to enumerate persisted anchor names: %d"), result);
delete[] xrNames;
}
UE_LOG(ViveOXRAnchor, Log, TEXT("Find: %d in collection"), nameCount);
for (uint32_t i = 0; i < nameCount; i++)
{
FString anchorName = ToFString(xrNames[i]);
UE_LOG(ViveOXRAnchor, Log, TEXT("EnumeratePersistedAnchorNames: %s"), *anchorName);
}
}
void FViveOpenXRAnchor::RemoveAllSavedARPins(XrSession InSession)
{
UE_LOG(ViveOXRAnchor, Log, TEXT("RemoveAllSavedARPins()"));
if (!IsLocalPinSaveSupported()) return;
CheckPersistedAnchorCollectionAR();
if (paCollectionAR == nullptr) {
// If supported, when ARSession started, it should be created. Developer Should check IsLocalPinSaveSupported first.
UE_LOG(ViveOXRAnchor, Error, TEXT("SaveARPin() Anchor persistence is not exist. Check IsLocalPinSaveSupported first."));
return;
}
auto ret = ClearPersistedAnchors(paCollectionAR);
if (ret != XR_SUCCESS) {
UE_LOG(ViveOXRAnchor, Error, TEXT("RemoveAllSavedARPins() ClearPersistedAnchors failed with result %d."), ret);
}
UE_LOG(ViveOXRAnchor, Log, TEXT("Collection :%p"), paCollectionAR);
UE_LOG(ViveOXRAnchor, Log, TEXT("Check collection all removed"));
// Check collection removed
uint32_t nameCount = 0;
XrSpatialAnchorNameHTC* xrNames = new XrSpatialAnchorNameHTC[nameCount];
FMemory::Memset(xrNames, 0, sizeof(XrSpatialAnchorNameHTC) * nameCount);
XrResult result = EnumeratePersistedAnchorNames((XrPersistedAnchorCollectionHTC)paCollectionAR, nameCount, &nameCount, xrNames);
if (XR_FAILED(result))
{
UE_LOG(ViveOXRAnchor, Error, TEXT("Failed to enumerate persisted anchor names: %d"), result);
delete[] xrNames;
}
UE_LOG(ViveOXRAnchor, Log, TEXT("Find: %d in collection"), nameCount);
for (uint32_t i = 0; i < nameCount; i++)
{
FString name = ToFString(xrNames[i]);
UE_LOG(ViveOXRAnchor, Log, TEXT("EnumeratePersistedAnchorNames: %s"), *name);
}
}