Android build settings + metaxr
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRRoomLayoutManagerComponent.h"
|
||||
#include "OculusXRScene.h"
|
||||
#include "OculusXRSceneModule.h"
|
||||
#include "OculusXRSceneDelegates.h"
|
||||
#include "OculusXRSceneFunctionLibrary.h"
|
||||
#include "ProceduralMeshComponent.h"
|
||||
|
||||
UOculusXRRoomLayoutManagerComponent::UOculusXRRoomLayoutManagerComponent(const FObjectInitializer& ObjectInitializer)
|
||||
{
|
||||
bWantsInitializeComponent = true; // so that InitializeComponent() gets called
|
||||
}
|
||||
|
||||
void UOculusXRRoomLayoutManagerComponent::OnRegister()
|
||||
{
|
||||
Super::OnRegister();
|
||||
|
||||
FOculusXRSceneEventDelegates::OculusSceneCaptureComplete.AddUObject(this, &UOculusXRRoomLayoutManagerComponent::OculusRoomLayoutSceneCaptureComplete_Handler);
|
||||
}
|
||||
|
||||
void UOculusXRRoomLayoutManagerComponent::OnUnregister()
|
||||
{
|
||||
Super::OnUnregister();
|
||||
|
||||
FOculusXRSceneEventDelegates::OculusSceneCaptureComplete.RemoveAll(this);
|
||||
}
|
||||
|
||||
void UOculusXRRoomLayoutManagerComponent::InitializeComponent()
|
||||
{
|
||||
Super::InitializeComponent();
|
||||
}
|
||||
|
||||
void UOculusXRRoomLayoutManagerComponent::UninitializeComponent()
|
||||
{
|
||||
Super::UninitializeComponent();
|
||||
}
|
||||
|
||||
bool UOculusXRRoomLayoutManagerComponent::LaunchCaptureFlow()
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("Launch capture flow -- UOculusXRRoomLayoutManagerComponent"));
|
||||
|
||||
uint64 OutRequest = 0;
|
||||
auto result = OculusXRScene::FOculusXRScene::RequestSceneCapture(OutRequest);
|
||||
bool isSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(result);
|
||||
if (isSuccess)
|
||||
{
|
||||
EntityRequestList.Add(OutRequest);
|
||||
}
|
||||
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("Launch capture flow -- RequestSceneCapture -- %d"), result);
|
||||
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
bool UOculusXRRoomLayoutManagerComponent::GetRoomLayout(FOculusXRUInt64 Space, FOculusXRRoomLayout& RoomLayoutOut, int32 MaxWallsCapacity)
|
||||
{
|
||||
return UOculusXRSceneFunctionLibrary::GetRoomLayout(Space, RoomLayoutOut, MaxWallsCapacity);
|
||||
}
|
||||
|
||||
bool UOculusXRRoomLayoutManagerComponent::LoadTriangleMesh(FOculusXRUInt64 Space, UProceduralMeshComponent* Mesh, bool CreateCollision) const
|
||||
{
|
||||
ensure(Mesh);
|
||||
TArray<FVector> Vertices;
|
||||
TArray<int32> Triangles;
|
||||
|
||||
auto result = OculusXRScene::FOculusXRScene::GetTriangleMesh(Space, Vertices, Triangles);
|
||||
bool isSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(result);
|
||||
if (!isSuccess)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mesh->bUseAsyncCooking = true;
|
||||
TArray<FVector> EmptyNormals;
|
||||
TArray<FVector2D> EmptyUV;
|
||||
TArray<FColor> EmptyVertexColors;
|
||||
TArray<FProcMeshTangent> EmptyTangents;
|
||||
Mesh->CreateMeshSection(0, Vertices, Triangles, EmptyNormals, EmptyUV, EmptyVertexColors, EmptyTangents, CreateCollision);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRScene.h"
|
||||
#include "OculusXRSceneModule.h"
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "OculusXRHMD.h"
|
||||
#include "OculusXRPluginWrapper.h"
|
||||
#include "OculusXRSceneFunctionsOVR.h"
|
||||
#include "OculusXRSceneFunctionsOpenXR.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "OculusXRScene"
|
||||
|
||||
namespace OculusXRScene
|
||||
{
|
||||
EOculusXRAnchorResult::Type FOculusXRScene::GetScenePlane(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize)
|
||||
{
|
||||
return GetOculusXRSceneFunctionsImpl()->GetScenePlane(AnchorHandle, OutPos, OutSize);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRScene::GetSceneVolume(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize)
|
||||
{
|
||||
return GetOculusXRSceneFunctionsImpl()->GetSceneVolume(AnchorHandle, OutPos, OutSize);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRScene::GetSemanticClassification(uint64 AnchorHandle, TArray<FString>& OutSemanticClassifications)
|
||||
{
|
||||
return GetOculusXRSceneFunctionsImpl()->GetSemanticClassification(AnchorHandle, OutSemanticClassifications);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRScene::GetBoundary2D(uint64 AnchorHandle, TArray<FVector2f>& OutVertices)
|
||||
{
|
||||
return GetOculusXRSceneFunctionsImpl()->GetBoundary2D(AnchorHandle, OutVertices);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRScene::RequestSceneCapture(uint64& OutRequestID)
|
||||
{
|
||||
return GetOculusXRSceneFunctionsImpl()->RequestSceneCapture(OutRequestID);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRScene::GetRoomLayout(uint64 AnchorHandle, const uint32 MaxWallsCapacity, FOculusXRUUID& OutCeilingUuid, FOculusXRUUID& OutFloorUuid, TArray<FOculusXRUUID>& OutWallsUuid)
|
||||
{
|
||||
return GetOculusXRSceneFunctionsImpl()->GetRoomLayout(AnchorHandle, MaxWallsCapacity, OutCeilingUuid, OutFloorUuid, OutWallsUuid);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRScene::GetTriangleMesh(uint64 AnchorHandle, TArray<FVector>& Vertices, TArray<int32>& Triangles)
|
||||
{
|
||||
return GetOculusXRSceneFunctionsImpl()->GetTriangleMesh(AnchorHandle, Vertices, Triangles);
|
||||
}
|
||||
|
||||
// Requests to change the current boundary visibility
|
||||
EOculusXRAnchorResult::Type FOculusXRScene::RequestBoundaryVisibility(EOculusXRBoundaryVisibility NewVisibilityRequest)
|
||||
{
|
||||
return GetOculusXRSceneFunctionsImpl()->RequestBoundaryVisibility(NewVisibilityRequest);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRScene::GetBoundaryVisibility(EOculusXRBoundaryVisibility& OutVisibility)
|
||||
{
|
||||
return GetOculusXRSceneFunctionsImpl()->GetBoundaryVisibility(OutVisibility);
|
||||
}
|
||||
|
||||
|
||||
TSharedPtr<IOculusXRSceneFunctions> FOculusXRScene::SceneFunctionsImpl = nullptr;
|
||||
|
||||
TSharedPtr<IOculusXRSceneFunctions> FOculusXRScene::GetOculusXRSceneFunctionsImpl()
|
||||
{
|
||||
if (SceneFunctionsImpl == nullptr)
|
||||
{
|
||||
const FName SystemName(TEXT("OpenXR"));
|
||||
const bool IsOpenXR = GEngine->XRSystem.IsValid() && (GEngine->XRSystem->GetSystemName() == SystemName);
|
||||
if (OculusXRHMD::FOculusXRHMD::GetOculusXRHMD() != nullptr)
|
||||
{
|
||||
SceneFunctionsImpl = MakeShared<FOculusXRSceneFunctionsOVR>();
|
||||
}
|
||||
else if (IsOpenXR)
|
||||
{
|
||||
SceneFunctionsImpl = MakeShared<FOculusXRSceneFunctionsOpenXR>();
|
||||
}
|
||||
}
|
||||
|
||||
check(SceneFunctionsImpl);
|
||||
return SceneFunctionsImpl;
|
||||
}
|
||||
} // namespace OculusXRScene
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,784 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRSceneActor.h"
|
||||
#include "OculusXRSceneModule.h"
|
||||
#include "OculusXRHMDModule.h"
|
||||
#include "OculusXRHMD.h"
|
||||
#include "OculusXRAnchorManager.h"
|
||||
#include "OculusXRAnchorTypes.h"
|
||||
#include "OculusXRAnchorBPFunctionLibrary.h"
|
||||
#include "OculusXRScene.h"
|
||||
#include "OculusXRSceneDelegates.h"
|
||||
#include "OculusXRDelegates.h"
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
#include "Engine/AssetManager.h"
|
||||
#include "Engine/StaticMesh.h"
|
||||
#include "Engine/StaticMeshActor.h"
|
||||
#include "Engine/World.h"
|
||||
#include "GameFramework/WorldSettings.h"
|
||||
#include "ProceduralMeshComponent.h"
|
||||
#include "OculusXRSceneGlobalMeshComponent.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "OculusXRSceneActor"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ASceneActor
|
||||
|
||||
AOculusXRSceneActor::AOculusXRSceneActor(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
ResetStates();
|
||||
|
||||
// Create required components
|
||||
RoomLayoutManagerComponent = CreateDefaultSubobject<UOculusXRRoomLayoutManagerComponent>(TEXT("OculusXRRoomLayoutManagerComponent"));
|
||||
|
||||
// Following are the semantic labels we want to support default properties for. User can always add new ones through the properties panel if needed.
|
||||
const FString default2DSemanticClassifications[] = {
|
||||
TEXT("WALL_FACE"),
|
||||
TEXT("CEILING"),
|
||||
TEXT("FLOOR"),
|
||||
TEXT("COUCH"),
|
||||
TEXT("TABLE"),
|
||||
TEXT("DOOR_FRAME"),
|
||||
TEXT("WINDOW_FRAME"),
|
||||
TEXT("WALL_ART"),
|
||||
TEXT("INVISIBLE_WALL_FACE"),
|
||||
TEXT("OTHER")
|
||||
};
|
||||
|
||||
const FString default3DSemanticClassifications[] = {
|
||||
TEXT("COUCH"),
|
||||
TEXT("TABLE"),
|
||||
TEXT("SCREEN"),
|
||||
TEXT("BED"),
|
||||
TEXT("LAMP"),
|
||||
TEXT("PLANT"),
|
||||
TEXT("STORAGE"),
|
||||
TEXT("OTHER")
|
||||
};
|
||||
|
||||
FOculusXRSpawnedSceneAnchorProperties spawnedAnchorProps;
|
||||
spawnedAnchorProps.ActorComponent = nullptr;
|
||||
spawnedAnchorProps.StaticMesh = nullptr;
|
||||
|
||||
// Setup initial scene plane and volume properties
|
||||
for (auto& semanticLabel2D : default2DSemanticClassifications)
|
||||
{
|
||||
FOculusXRSpawnedSceneAnchorProperties& props = ScenePlaneSpawnedSceneAnchorProperties.Add(semanticLabel2D, spawnedAnchorProps);
|
||||
props.ForceParallelToFloor = (semanticLabel2D != "WALL_FACE");
|
||||
}
|
||||
|
||||
for (auto& semanticLabel3D : default3DSemanticClassifications)
|
||||
{
|
||||
FOculusXRSpawnedSceneAnchorProperties& props = SceneVolumeSpawnedSceneAnchorProperties.Add(semanticLabel3D, spawnedAnchorProps);
|
||||
props.ForceParallelToFloor = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::ResetStates()
|
||||
{
|
||||
bCaptureFlowWasLaunched = false;
|
||||
ClearScene();
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
// Create a scene component as root so we can attach spawned actors to it
|
||||
USceneComponent* rootSceneComponent = NewObject<USceneComponent>(this, USceneComponent::StaticClass());
|
||||
rootSceneComponent->SetMobility(EComponentMobility::Static);
|
||||
rootSceneComponent->RegisterComponent();
|
||||
SetRootComponent(rootSceneComponent);
|
||||
|
||||
SceneGlobalMeshComponent = FindComponentByClass<UOculusXRSceneGlobalMeshComponent>();
|
||||
|
||||
// Register delegates
|
||||
RoomLayoutManagerComponent->OculusXRRoomLayoutSceneCaptureCompleteNative.AddUObject(this, &AOculusXRSceneActor::SceneCaptureComplete_Handler);
|
||||
|
||||
// Make an initial request to query for the room layout if bPopulateSceneOnBeginPlay was set to true
|
||||
if (bPopulateSceneOnBeginPlay)
|
||||
{
|
||||
PopulateScene();
|
||||
}
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::EndPlay(EEndPlayReason::Type Reason)
|
||||
{
|
||||
// Unregister delegates
|
||||
RoomLayoutManagerComponent->OculusXRRoomLayoutSceneCaptureCompleteNative.RemoveAll(this);
|
||||
|
||||
// Calling ResetStates will reset member variables to their default values (including the request IDs).
|
||||
ResetStates();
|
||||
|
||||
Super::EndPlay(Reason);
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
}
|
||||
|
||||
bool AOculusXRSceneActor::IsValidUuid(const FOculusXRUUID& Uuid)
|
||||
{
|
||||
return Uuid.UUIDBytes != nullptr;
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::LaunchCaptureFlow()
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("Launch capture flow"));
|
||||
|
||||
if (RoomLayoutManagerComponent)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("Launch capture flow -- RoomLayoutManagerComponent"));
|
||||
|
||||
const bool bResult = RoomLayoutManagerComponent->LaunchCaptureFlow();
|
||||
if (!bResult)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("LaunchCaptureFlow() failed!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::LaunchCaptureFlowIfNeeded()
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
UE_LOG(LogOculusXRScene, Display, TEXT("Scene Capture does not work over Link. Please capture a scene with the HMD in standalone mode, then access the scene model over Link."));
|
||||
#else
|
||||
// Depending on LauchCaptureFlowWhenMissingScene, we might not want to launch Capture Flow
|
||||
if (LauchCaptureFlowWhenMissingScene != EOculusXRLaunchCaptureFlowWhenMissingScene::NEVER)
|
||||
{
|
||||
if (LauchCaptureFlowWhenMissingScene == EOculusXRLaunchCaptureFlowWhenMissingScene::ALWAYS || (!bCaptureFlowWasLaunched && LauchCaptureFlowWhenMissingScene == EOculusXRLaunchCaptureFlowWhenMissingScene::ONCE))
|
||||
{
|
||||
LaunchCaptureFlow();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
AActor* AOculusXRSceneActor::SpawnActorWithSceneComponent(const FOculusXRUInt64& Space, const FOculusXRUInt64& RoomSpaceID, const TArray<FString>& SemanticClassifications, UClass* sceneAnchorComponentInstanceClass)
|
||||
{
|
||||
FActorSpawnParameters actorSpawnParams;
|
||||
actorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
|
||||
AActor* Anchor = GetWorld()->SpawnActor<AActor>(AActor::StaticClass(), FVector::ZeroVector, FRotator::ZeroRotator, actorSpawnParams);
|
||||
|
||||
USceneComponent* rootComponent = NewObject<USceneComponent>(Anchor, USceneComponent::StaticClass());
|
||||
rootComponent->SetMobility(EComponentMobility::Movable);
|
||||
rootComponent->RegisterComponent();
|
||||
Anchor->SetRootComponent(rootComponent);
|
||||
rootComponent->SetWorldLocation(FVector::ZeroVector);
|
||||
|
||||
Anchor->AttachToActor(this, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
|
||||
#if WITH_EDITOR
|
||||
if (SemanticClassifications.Num() > 0)
|
||||
{
|
||||
Anchor->SetActorLabel(FString::Join(SemanticClassifications, TEXT("-")), false);
|
||||
}
|
||||
#endif
|
||||
|
||||
UOculusXRSceneAnchorComponent* sceneAnchorComponent = NewObject<UOculusXRSceneAnchorComponent>(Anchor, sceneAnchorComponentInstanceClass);
|
||||
sceneAnchorComponent->RegisterComponent();
|
||||
|
||||
sceneAnchorComponent->SetHandle(Space);
|
||||
sceneAnchorComponent->SemanticClassifications = SemanticClassifications;
|
||||
sceneAnchorComponent->RoomSpaceID = RoomSpaceID;
|
||||
|
||||
EOculusXRAnchorResult::Type Result;
|
||||
OculusXRAnchors::FOculusXRAnchors::SetAnchorComponentStatus(sceneAnchorComponent, EOculusXRSpaceComponentType::Locatable, true, 0.0f, FOculusXRAnchorSetComponentStatusDelegate(), Result);
|
||||
|
||||
return Anchor;
|
||||
}
|
||||
|
||||
AActor* AOculusXRSceneActor::SpawnOrUpdateSceneAnchor(AActor* Anchor, const FOculusXRUInt64& Space, const FOculusXRUInt64& RoomSpaceID, const FVector& BoundedPos, const FVector& BoundedSize, const TArray<FString>& SemanticClassifications, const EOculusXRSpaceComponentType AnchorComponentType)
|
||||
{
|
||||
if (Space.Value == 0)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("AOculusXRSceneActor::SpawnOrUpdateSceneAnchor Invalid Space handle."));
|
||||
return Anchor;
|
||||
}
|
||||
|
||||
if (!(AnchorComponentType == EOculusXRSpaceComponentType::ScenePlane || AnchorComponentType == EOculusXRSpaceComponentType::SceneVolume))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("AOculusXRSceneActor::SpawnOrUpdateSceneAnchor Anchor doesn't have ScenePlane or SceneVolume component active."));
|
||||
return Anchor;
|
||||
}
|
||||
|
||||
if (0 == SemanticClassifications.Num())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("AOculusXRSceneActor::SpawnOrUpdateSceneAnchor No semantic classification found."));
|
||||
return Anchor;
|
||||
}
|
||||
|
||||
FOculusXRSpawnedSceneAnchorProperties* foundProperties = (AnchorComponentType == EOculusXRSpaceComponentType::ScenePlane) ? ScenePlaneSpawnedSceneAnchorProperties.Find(SemanticClassifications[0]) : SceneVolumeSpawnedSceneAnchorProperties.Find(SemanticClassifications[0]);
|
||||
|
||||
if (!foundProperties)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("AOculusXRSceneActor::SpawnOrUpdateSceneAnchor Scene object has an unknown semantic label. Will not be spawned."));
|
||||
return Anchor;
|
||||
}
|
||||
|
||||
TSoftClassPtr<UOculusXRSceneAnchorComponent>* sceneAnchorComponentClassPtrRef = &foundProperties->ActorComponent;
|
||||
TSoftObjectPtr<UStaticMesh>* staticMeshObjPtrRef = &foundProperties->StaticMesh;
|
||||
|
||||
UClass* sceneAnchorComponentInstanceClass = sceneAnchorComponentClassPtrRef->LoadSynchronous();
|
||||
if (!sceneAnchorComponentInstanceClass)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("AOculusXRSceneActor::SpawnOrUpdateSceneAnchor Scene anchor component class is invalid! Cannot spawn actor to populate the scene."));
|
||||
return Anchor;
|
||||
}
|
||||
|
||||
if (!Anchor)
|
||||
{
|
||||
Anchor = SpawnActorWithSceneComponent(Space, RoomSpaceID, SemanticClassifications, sceneAnchorComponentInstanceClass);
|
||||
}
|
||||
|
||||
if (staticMeshObjPtrRef && staticMeshObjPtrRef->IsPending())
|
||||
{
|
||||
staticMeshObjPtrRef->LoadSynchronous();
|
||||
}
|
||||
UStaticMesh* refStaticMesh = staticMeshObjPtrRef ? staticMeshObjPtrRef->Get() : nullptr;
|
||||
if (refStaticMesh == nullptr)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("AOculusXRSceneActor::SpawnOrUpdateSceneAnchor Spawn scene anchor mesh is invalid for %s!"), *SemanticClassifications[0]);
|
||||
return Anchor;
|
||||
}
|
||||
|
||||
UStaticMeshComponent* staticMeshComponent = NewObject<UStaticMeshComponent>(Anchor, UStaticMeshComponent::StaticClass());
|
||||
staticMeshComponent->RegisterComponent();
|
||||
staticMeshComponent->SetStaticMesh(refStaticMesh);
|
||||
staticMeshComponent->AttachToComponent(Anchor->GetRootComponent(), FAttachmentTransformRules::KeepWorldTransform);
|
||||
const float worldToMeters = GetWorld()->GetWorldSettings()->WorldToMeters;
|
||||
FVector offset(0.0f, BoundedSize.Y / 2.0f, BoundedSize.Z / 2.0f);
|
||||
staticMeshComponent->SetRelativeLocation(foundProperties->AddOffset + ((BoundedPos + offset) * worldToMeters), false, nullptr, ETeleportType::ResetPhysics);
|
||||
|
||||
// Setup scale based on bounded size and the actual size of the mesh
|
||||
UStaticMesh* staticMesh = staticMeshComponent->GetStaticMesh();
|
||||
FBoxSphereBounds staticMeshBounds;
|
||||
staticMeshBounds.BoxExtent = FVector{ 1.f, 1.f, 1.f };
|
||||
if (staticMesh)
|
||||
{
|
||||
staticMeshBounds = staticMesh->GetBounds();
|
||||
}
|
||||
|
||||
staticMeshComponent->SetRelativeScale3D(FVector(
|
||||
(BoundedSize.X < UE_SMALL_NUMBER) ? 1 : (BoundedSize.X / (staticMeshBounds.BoxExtent.X * 2.f)) * worldToMeters,
|
||||
(BoundedSize.Y < UE_SMALL_NUMBER) ? 1 : (BoundedSize.Y / (staticMeshBounds.BoxExtent.Y * 2.f)) * worldToMeters,
|
||||
(BoundedSize.Z < UE_SMALL_NUMBER) ? 1 : (BoundedSize.Z / (staticMeshBounds.BoxExtent.Z * 2.f)) * worldToMeters));
|
||||
|
||||
return Anchor;
|
||||
}
|
||||
|
||||
bool AOculusXRSceneActor::IsScenePopulated()
|
||||
{
|
||||
if (!RootComponent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return RootComponent->GetNumChildrenComponents() > 0;
|
||||
}
|
||||
|
||||
bool AOculusXRSceneActor::IsRoomLayoutValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::PopulateScene()
|
||||
{
|
||||
if (!RootComponent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const EOculusXRAnchorResult::Type result = QueryAllRooms();
|
||||
if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(result))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("PopulateScene Failed to query available rooms"));
|
||||
}
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::ClearScene()
|
||||
{
|
||||
if (!RootComponent)
|
||||
return;
|
||||
|
||||
TArray<USceneComponent*> childrenComponents = RootComponent->GetAttachChildren();
|
||||
for (USceneComponent* SceneComponent : childrenComponents)
|
||||
{
|
||||
Cast<AActor>(SceneComponent->GetOuter())->Destroy();
|
||||
}
|
||||
|
||||
bRoomLayoutIsValid = false;
|
||||
bFoundCapturedScene = false;
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::SetVisibilityToAllSceneAnchors(const bool bIsVisible)
|
||||
{
|
||||
if (!RootComponent)
|
||||
return;
|
||||
|
||||
TArray<USceneComponent*> childrenComponents = RootComponent->GetAttachChildren();
|
||||
for (USceneComponent* sceneComponent : childrenComponents)
|
||||
{
|
||||
sceneComponent->SetVisibility(bIsVisible, true);
|
||||
}
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::SetVisibilityToSceneAnchorsBySemanticLabel(const FString SemanticLabel, const bool bIsVisible)
|
||||
{
|
||||
FString label = SemanticLabel;
|
||||
if (SemanticLabel == TEXT("DESK"))
|
||||
{
|
||||
label = TEXT("TABLE");
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("XR Scene Actor semantic lable 'DESK' is deprecated, use 'TABLE' instead."));
|
||||
}
|
||||
|
||||
if (!RootComponent)
|
||||
return;
|
||||
|
||||
TArray<USceneComponent*> childrenComponents = RootComponent->GetAttachChildren();
|
||||
for (USceneComponent* sceneComponent : childrenComponents)
|
||||
{
|
||||
UObject* outerObject = sceneComponent->GetOuter();
|
||||
if (!outerObject)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AActor* outerActor = Cast<AActor>(outerObject);
|
||||
if (!outerActor)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UActorComponent* sceneAnchorComponent = outerActor->GetComponentByClass(UOculusXRSceneAnchorComponent::StaticClass());
|
||||
if (!sceneAnchorComponent)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Cast<UOculusXRSceneAnchorComponent>(sceneAnchorComponent)->SemanticClassifications.Contains(label))
|
||||
{
|
||||
sceneComponent->SetVisibility(bIsVisible, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TArray<AActor*> AOculusXRSceneActor::GetActorsBySemanticLabel(const FString SemanticLabel)
|
||||
{
|
||||
FString label = SemanticLabel;
|
||||
if (SemanticLabel == TEXT("DESK"))
|
||||
{
|
||||
label = TEXT("TABLE");
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("XR Scene Actor semantic lable 'DESK' is deprecated, use 'TABLE' instead."));
|
||||
}
|
||||
|
||||
TArray<AActor*> actors;
|
||||
|
||||
if (!RootComponent)
|
||||
return actors;
|
||||
|
||||
TArray<USceneComponent*> childrenComponents = RootComponent->GetAttachChildren();
|
||||
for (USceneComponent* sceneComponent : childrenComponents)
|
||||
{
|
||||
UObject* outerObject = sceneComponent->GetOuter();
|
||||
if (!outerObject)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AActor* outerActor = Cast<AActor>(outerObject);
|
||||
if (!outerActor)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UActorComponent* sceneAnchorComponent = outerActor->GetComponentByClass(UOculusXRSceneAnchorComponent::StaticClass());
|
||||
if (!sceneAnchorComponent)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Cast<UOculusXRSceneAnchorComponent>(sceneAnchorComponent)->SemanticClassifications.Contains(label))
|
||||
{
|
||||
actors.Add(outerActor);
|
||||
}
|
||||
}
|
||||
|
||||
return actors;
|
||||
}
|
||||
|
||||
TArray<FOculusXRRoomLayout> AOculusXRSceneActor::GetRoomLayouts() const
|
||||
{
|
||||
TArray<FOculusXRRoomLayout> layouts;
|
||||
RoomLayouts.GenerateValueArray(layouts);
|
||||
return layouts;
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type AOculusXRSceneActor::QueryAllRooms()
|
||||
{
|
||||
EOculusXRAnchorResult::Type anchorQueryResult;
|
||||
|
||||
auto componentFilter = NewObject<UOculusXRSpaceDiscoveryComponentsFilter>(this);
|
||||
componentFilter->ComponentType = EOculusXRSpaceComponentType::RoomLayout;
|
||||
|
||||
FOculusXRSpaceDiscoveryInfo discoveryInfo;
|
||||
discoveryInfo.Filters.Add(componentFilter);
|
||||
|
||||
OculusXRAnchors::FOculusXRAnchors::DiscoverAnchors(discoveryInfo,
|
||||
FOculusXRDiscoverAnchorsResultsDelegate::CreateUObject(this, &AOculusXRSceneActor::RoomLayoutDiscoveryResultsAvailable),
|
||||
FOculusXRDiscoverAnchorsCompleteDelegate(),
|
||||
anchorQueryResult);
|
||||
|
||||
return anchorQueryResult;
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::RoomLayoutDiscoveryResultsAvailable(const TArray<FOculusXRAnchorsDiscoverResult>& QueryResults)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("RoomLayoutDiscoveryResultsAvailable"));
|
||||
|
||||
for (auto& QueryElement : QueryResults)
|
||||
{
|
||||
ProcessRoomQueryResult(QueryElement.Space, QueryElement.UUID);
|
||||
}
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::ProcessRoomQueryResult(FOculusXRUInt64 AnchorHandle, FOculusXRUUID UUID)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("Process Room Query Result -- Query Element (space = %llu, uuid = %s"), AnchorHandle.Value, *BytesToHex(UUID.UUIDBytes, OCULUSXR_UUID_SIZE));
|
||||
|
||||
FOculusXRRoomLayout roomLayout;
|
||||
const bool bGetRoomLayoutResult = RoomLayoutManagerComponent->GetRoomLayout(AnchorHandle.Value, roomLayout, MaxQueries);
|
||||
if (!bGetRoomLayoutResult)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("Process Room Query Result -- Failed to get room layout for space (space = %llu, uuid = %s"),
|
||||
AnchorHandle.Value, *BytesToHex(UUID.UUIDBytes, OCULUSXR_UUID_SIZE));
|
||||
return;
|
||||
}
|
||||
|
||||
roomLayout.RoomAnchorHandle = AnchorHandle;
|
||||
roomLayout.RoomUuid = UUID;
|
||||
|
||||
|
||||
// If we're only loading the active room we start that floor check query here, otherwise do the room query
|
||||
if (bActiveRoomOnly)
|
||||
{
|
||||
QueryFloorForActiveRoom(AnchorHandle, roomLayout);
|
||||
}
|
||||
else
|
||||
{
|
||||
StartSingleRoomQuery(AnchorHandle, roomLayout);
|
||||
}
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type AOculusXRSceneActor::QueryRoomUUIDs(const FOculusXRUInt64 RoomSpaceID, const TArray<FOculusXRUUID>& RoomUUIDs)
|
||||
{
|
||||
EOculusXRAnchorResult::Type startAnchorQueryResult;
|
||||
|
||||
auto uuidFilter = NewObject<UOculusXRSpaceDiscoveryIdsFilter>(this);
|
||||
uuidFilter->Uuids = RoomUUIDs;
|
||||
|
||||
FOculusXRSpaceDiscoveryInfo discoveryInfo;
|
||||
discoveryInfo.Filters.Add(uuidFilter);
|
||||
|
||||
OculusXRAnchors::FOculusXRAnchors::DiscoverAnchors(discoveryInfo,
|
||||
FOculusXRDiscoverAnchorsResultsDelegate::CreateUObject(this, &AOculusXRSceneActor::SceneRoomDiscoveryResultsAvailable, RoomSpaceID),
|
||||
FOculusXRDiscoverAnchorsCompleteDelegate(),
|
||||
startAnchorQueryResult);
|
||||
|
||||
return startAnchorQueryResult;
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::SceneRoomDiscoveryResultsAvailable(const TArray<FOculusXRAnchorsDiscoverResult>& DiscoveryResults, const FOculusXRUInt64 RoomSpaceID)
|
||||
{
|
||||
for (auto& AnchorQueryElement : DiscoveryResults)
|
||||
{
|
||||
ProcessRoomElementsResult(AnchorQueryElement.Space, RoomSpaceID);
|
||||
}
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::ProcessRoomElementsResult(FOculusXRUInt64 AnchorHandle, const FOculusXRUInt64 RoomSpaceID)
|
||||
{
|
||||
bool bOutPending = false;
|
||||
|
||||
if (SceneGlobalMeshComponent)
|
||||
{
|
||||
TArray<FString> semanticClassifications;
|
||||
GetSemanticClassifications(AnchorHandle.Value, semanticClassifications);
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT("SpatialAnchor Scene label is %s"), semanticClassifications.Num() > 0 ? *semanticClassifications[0] : TEXT("unknown"));
|
||||
if (semanticClassifications.Contains(UOculusXRSceneGlobalMeshComponent::GlobalMeshSemanticLabel))
|
||||
{
|
||||
bool bIsTriangleMesh = false;
|
||||
EOculusXRAnchorResult::Type result = OculusXRAnchors::FOculusXRAnchorManager::GetAnchorComponentStatus(
|
||||
AnchorHandle.Value, EOculusXRSpaceComponentType::TriangleMesh, bIsTriangleMesh, bOutPending);
|
||||
|
||||
if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(result) || !bIsTriangleMesh)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("SpatialAnchorQueryResult_Handler Failed to load Triangle Mesh Component for a GLOBAL_MESH"));
|
||||
return;
|
||||
}
|
||||
|
||||
UClass* sceneAnchorComponentInstanceClass = SceneGlobalMeshComponent->GetAnchorComponentClass();
|
||||
|
||||
AActor* globalMeshAnchor = SpawnActorWithSceneComponent(AnchorHandle.Value, RoomSpaceID, semanticClassifications, sceneAnchorComponentInstanceClass);
|
||||
|
||||
SceneGlobalMeshComponent->CreateMeshComponent(AnchorHandle, globalMeshAnchor, RoomLayoutManagerComponent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool bIsScenePlane = false;
|
||||
bool bIsSceneVolume = false;
|
||||
EOculusXRAnchorResult::Type isPlaneResult = OculusXRAnchors::FOculusXRAnchorManager::GetAnchorComponentStatus(
|
||||
AnchorHandle.Value, EOculusXRSpaceComponentType::ScenePlane, bIsScenePlane, bOutPending);
|
||||
|
||||
EOculusXRAnchorResult::Type isVolumeResult = OculusXRAnchors::FOculusXRAnchorManager::GetAnchorComponentStatus(
|
||||
AnchorHandle.Value, EOculusXRSpaceComponentType::SceneVolume, bIsSceneVolume, bOutPending);
|
||||
|
||||
bool bIsPlaneResultSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(isPlaneResult);
|
||||
bool bIsVolumeResultSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(isVolumeResult);
|
||||
|
||||
AActor* anchor = nullptr;
|
||||
|
||||
if (bIsPlaneResultSuccess && bIsScenePlane)
|
||||
{
|
||||
FVector scenePlanePos;
|
||||
FVector scenePlaneSize;
|
||||
auto getScenePlaneResult = OculusXRScene::FOculusXRScene::GetScenePlane(AnchorHandle.Value, scenePlanePos, scenePlaneSize);
|
||||
if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(getScenePlaneResult))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT("SpatialAnchorQueryResult_Handler ScenePlane pos = [%.2f, %.2f, %.2f], size = [%.2f, %.2f, %.2f]."),
|
||||
scenePlanePos.X, scenePlanePos.Y, scenePlanePos.Z,
|
||||
scenePlaneSize.X, scenePlaneSize.Y, scenePlaneSize.Z);
|
||||
|
||||
TArray<FString> semanticClassifications;
|
||||
GetSemanticClassifications(AnchorHandle.Value, semanticClassifications);
|
||||
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT("SpatialAnchor ScenePlane label is %s"), semanticClassifications.Num() > 0 ? *semanticClassifications[0] : TEXT("unknown"));
|
||||
|
||||
anchor = SpawnOrUpdateSceneAnchor(anchor, AnchorHandle, RoomSpaceID, scenePlanePos, scenePlaneSize, semanticClassifications, EOculusXRSpaceComponentType::ScenePlane);
|
||||
if (!anchor)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("SpatialAnchorQueryResult_Handler Failed to spawn scene anchor."));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("SpatialAnchorQueryResult_Handler Failed to get bounds for ScenePlane space."));
|
||||
}
|
||||
}
|
||||
|
||||
if (bIsVolumeResultSuccess && bIsSceneVolume)
|
||||
{
|
||||
FVector sceneVolumePos;
|
||||
FVector sceneVolumeSize;
|
||||
auto getSceneVolumeResult = OculusXRScene::FOculusXRScene::GetSceneVolume(AnchorHandle.Value, sceneVolumePos, sceneVolumeSize);
|
||||
if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(getSceneVolumeResult))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT("SpatialAnchorQueryResult_Handler SceneVolume pos = [%.2f, %.2f, %.2f], size = [%.2f, %.2f, %.2f]."),
|
||||
sceneVolumePos.X, sceneVolumePos.Y, sceneVolumePos.Z,
|
||||
sceneVolumeSize.X, sceneVolumeSize.Y, sceneVolumeSize.Z);
|
||||
|
||||
TArray<FString> semanticClassifications;
|
||||
GetSemanticClassifications(AnchorHandle.Value, semanticClassifications);
|
||||
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT("SpatialAnchor SceneVolume label is %s"), semanticClassifications.Num() > 0 ? *semanticClassifications[0] : TEXT("unknown"));
|
||||
|
||||
anchor = SpawnOrUpdateSceneAnchor(anchor, AnchorHandle, RoomSpaceID, sceneVolumePos, sceneVolumeSize, semanticClassifications, EOculusXRSpaceComponentType::SceneVolume);
|
||||
if (!anchor)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("SpatialAnchorQueryResult_Handler Failed to spawn scene anchor."));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("SpatialAnchorQueryResult_Handler Failed to get bounds for SceneVolume space."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::StartSingleRoomQuery(FOculusXRUInt64 RoomSpaceID, FOculusXRRoomLayout RoomLayout)
|
||||
{
|
||||
EOculusXRAnchorResult::Type startQueryResult = QueryRoomUUIDs(RoomSpaceID, RoomLayout.RoomObjectUUIDs);
|
||||
if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(startQueryResult))
|
||||
{
|
||||
RoomLayouts.Add(RoomSpaceID, std::move(RoomLayout));
|
||||
}
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type AOculusXRSceneActor::QueryFloorForActiveRoom(FOculusXRUInt64 RoomSpaceID, FOculusXRRoomLayout RoomLayout)
|
||||
{
|
||||
EOculusXRAnchorResult::Type anchorQueryResult;
|
||||
|
||||
auto uuidFilter = NewObject<UOculusXRSpaceDiscoveryIdsFilter>(this);
|
||||
uuidFilter->Uuids = { RoomLayout.FloorUuid };
|
||||
|
||||
FOculusXRSpaceDiscoveryInfo discoveryInfo;
|
||||
discoveryInfo.Filters.Add(uuidFilter);
|
||||
|
||||
OculusXRAnchors::FOculusXRAnchors::DiscoverAnchors(discoveryInfo,
|
||||
FOculusXRDiscoverAnchorsResultsDelegate::CreateUObject(this, &AOculusXRSceneActor::ActiveRoomFloorDiscoveryResultsAvailable, RoomSpaceID, RoomLayout),
|
||||
FOculusXRDiscoverAnchorsCompleteDelegate(),
|
||||
anchorQueryResult);
|
||||
|
||||
return anchorQueryResult;
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::ActiveRoomFloorDiscoveryResultsAvailable(const TArray<FOculusXRAnchorsDiscoverResult>& DiscoveryResults, FOculusXRUInt64 RoomSpaceID, FOculusXRRoomLayout RoomLayout)
|
||||
{
|
||||
if (DiscoveryResults.Num() != 1)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("Wrong number of elements returned from discover anchors for floor UUID. Result count (%d), UUID (%s), Room Space ID (%llu)"), DiscoveryResults.Num(), *RoomLayout.FloorUuid.ToString(), RoomSpaceID.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
const FOculusXRAnchorsDiscoverResult& floorQueryResult = DiscoveryResults[0];
|
||||
if (!CheckFloorBounds(floorQueryResult.Space, floorQueryResult.UUID, RoomLayout.RoomAnchorHandle))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("User is not within bounds of queried floor in room. UUID (%s), Room Space ID (%llu)"), *floorQueryResult.UUID.ToString(), RoomLayout.RoomAnchorHandle.GetValue());
|
||||
return;
|
||||
}
|
||||
|
||||
StartSingleRoomQuery(RoomSpaceID, RoomLayout);
|
||||
}
|
||||
|
||||
bool AOculusXRSceneActor::CheckFloorBounds(FOculusXRUInt64 AnchorHandle, FOculusXRUUID UUID, FOculusXRUInt64 RoomAnchorHandle)
|
||||
{
|
||||
TArray<FString> semanticClassifications;
|
||||
GetSemanticClassifications(AnchorHandle, semanticClassifications);
|
||||
if (!semanticClassifications.Contains("FLOOR"))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("Queried floor in room doesn't contain a floor semantic label. UUID (%s), Room Space ID (%llu)"), *UUID.ToString(), RoomAnchorHandle.GetValue());
|
||||
return false;
|
||||
}
|
||||
|
||||
TArray<FVector2f> boundaryVertices;
|
||||
EOculusXRAnchorResult::Type getBoundaryResult = OculusXRScene::FOculusXRScene::GetBoundary2D(AnchorHandle, boundaryVertices);
|
||||
if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(getBoundaryResult))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("Failed to get space boundary vertices for floor. UUID (%s), Room Space ID (%llu)"), *UUID.ToString(), RoomAnchorHandle.GetValue());
|
||||
return false;
|
||||
}
|
||||
|
||||
FQuat HMDOrientation;
|
||||
FVector HMDPosition;
|
||||
GEngine->XRSystem->GetCurrentPose(IXRTrackingSystem::HMDDeviceId, HMDOrientation, HMDPosition);
|
||||
|
||||
float scale = GEngine->XRSystem->GetWorldToMetersScale();
|
||||
|
||||
TArray<FVector> convertedBoundaryPoints;
|
||||
|
||||
FTransform floorTransform;
|
||||
if (!UOculusXRAnchorBPFunctionLibrary::GetAnchorTransformByHandle(AnchorHandle, floorTransform))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("Failed to get the floor anchor transform. Floor Space ID (%llu)"), AnchorHandle.GetValue());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert the boundary vertices to game engine world space
|
||||
for (auto& it : boundaryVertices)
|
||||
{
|
||||
FVector pos = floorTransform.TransformPosition(FVector(0, it.X * scale, it.Y * scale));
|
||||
convertedBoundaryPoints.Add(pos);
|
||||
}
|
||||
|
||||
// Create the new 2D boundary
|
||||
TArray<FVector2f> new2DBoundary;
|
||||
for (auto& it : convertedBoundaryPoints)
|
||||
{
|
||||
new2DBoundary.Add(FVector2f(it.X, it.Y));
|
||||
}
|
||||
|
||||
// Check if inside poly
|
||||
if (!PointInPolygon2D(FVector2f(HMDPosition.X, HMDPosition.Y), new2DBoundary))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("Floor failed active room check. UUID (%s), Room Space ID (%llu)"), *UUID.ToString(), RoomAnchorHandle.GetValue());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AOculusXRSceneActor::PointInPolygon2D(FVector2f PointToTest, const TArray<FVector2f>& PolyVerts) const
|
||||
{
|
||||
if (PolyVerts.Num() < 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int collision = 0;
|
||||
float x = PointToTest.X;
|
||||
float y = PointToTest.Y;
|
||||
|
||||
int vertCount = PolyVerts.Num();
|
||||
for (int i = 0; i < vertCount; i++)
|
||||
{
|
||||
float x1 = PolyVerts[i].X;
|
||||
float y1 = PolyVerts[i].Y;
|
||||
|
||||
float x2 = PolyVerts[(i + 1) % vertCount].X;
|
||||
float y2 = PolyVerts[(i + 1) % vertCount].Y;
|
||||
|
||||
if (y < y1 != y < y2 && x < x1 + ((y - y1) / (y2 - y1)) * (x2 - x1))
|
||||
{
|
||||
collision += (y1 < y2) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
return collision != 0;
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::GetSemanticClassifications(uint64 Space, TArray<FString>& OutSemanticLabels) const
|
||||
{
|
||||
EOculusXRAnchorResult::Type semanticLabelAnchorResult = OculusXRScene::FOculusXRScene::GetSemanticClassification(Space, OutSemanticLabels);
|
||||
if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(semanticLabelAnchorResult))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("GetSemanticClassifications -- Space (%llu) Classifications:"), Space);
|
||||
for (FString& label : OutSemanticLabels)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("%s"), *label);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("SpatialAnchorQueryResult_Handler Failed to get semantic classification space."));
|
||||
}
|
||||
}
|
||||
|
||||
// DELEGATE HANDLERS
|
||||
void AOculusXRSceneActor::SceneCaptureComplete_Handler(FOculusXRUInt64 RequestId, bool bResult)
|
||||
{
|
||||
if (!bResult)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("Scene Capture Complete failed!"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark that we already launched Capture Flow and try to query spatial anchors again
|
||||
bCaptureFlowWasLaunched = true;
|
||||
|
||||
ClearScene();
|
||||
PopulateScene();
|
||||
}
|
||||
|
||||
void AOculusXRSceneActor::PostLoad()
|
||||
{
|
||||
Super::PostLoad();
|
||||
|
||||
FOculusXRSpawnedSceneAnchorProperties desk;
|
||||
if (ScenePlaneSpawnedSceneAnchorProperties.RemoveAndCopyValue(TEXT("DESK"), desk))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT("Running XR Scene Actor plane semantic lable migration: 'DESK' to 'TABLE'"));
|
||||
ScenePlaneSpawnedSceneAnchorProperties[TEXT("TABLE")] = desk;
|
||||
}
|
||||
|
||||
if (SceneVolumeSpawnedSceneAnchorProperties.RemoveAndCopyValue(TEXT("DESK"), desk))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT("Running XR Scene Actor volume semantic lable migration: 'DESK' to 'TABLE'"));
|
||||
SceneVolumeSpawnedSceneAnchorProperties[TEXT("TABLE")] = desk;
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSceneAnchorComponent.h"
|
||||
|
||||
#include "Engine/StaticMeshActor.h"
|
||||
|
||||
UOculusXRSceneAnchorComponent::UOculusXRSceneAnchorComponent(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
bUpdateHeadSpaceTransform = false;
|
||||
}
|
||||
|
||||
void UOculusXRSceneAnchorComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||
{
|
||||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||
|
||||
if (GetHandle().Value == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSceneComponents.h"
|
||||
#include "OculusXRScene.h"
|
||||
#include "OculusXRSceneModule.h"
|
||||
#include "OculusXRAnchorBPFunctionLibrary.h"
|
||||
|
||||
bool UOculusXRPlaneAnchorComponent::GetPositionAndSize(FVector& outPosition, FVector& outSize) const
|
||||
{
|
||||
ensure(IsComponentEnabled());
|
||||
|
||||
if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OculusXRScene::FOculusXRScene::GetScenePlane(Space, outPosition, outSize)))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("Fetching scene plane failed."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UOculusXRVolumeAnchorComponent::GetPositionAndSize(FVector& outPosition, FVector& outSize) const
|
||||
{
|
||||
ensure(IsComponentEnabled());
|
||||
|
||||
if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OculusXRScene::FOculusXRScene::GetSceneVolume(Space, outPosition, outSize)))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("Fetching scene plane failed."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UOculusXRSemanticClassificationAnchorComponent::GetSemanticClassifications(TArray<FString>& outClassifications) const
|
||||
{
|
||||
ensure(IsComponentEnabled());
|
||||
|
||||
if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OculusXRScene::FOculusXRScene::GetSemanticClassification(Space, outClassifications)))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("Fetching scene volume failed."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UOculusXRRoomLayoutAnchorComponent::GetRoomLayout(FOculusXRUUID& outFloorUUID, FOculusXRUUID& outCeilingUUID, TArray<FOculusXRUUID>& outWallsUUIDs) const
|
||||
{
|
||||
ensure(IsComponentEnabled());
|
||||
|
||||
auto result = OculusXRScene::FOculusXRScene::GetRoomLayout(Space, 64, outCeilingUUID, outFloorUUID, outWallsUUIDs);
|
||||
if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(result))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("Fetching room layout failed."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSceneDelegates.h"
|
||||
|
||||
FOculusXRSceneEventDelegates::FOculusXRBoundaryVisibilityChanged FOculusXRSceneEventDelegates::OculusBoundaryVisibilityChanged;
|
||||
|
||||
FOculusXRSceneEventDelegates::FOculusXRSceneCaptureCompleteDelegate FOculusXRSceneEventDelegates::OculusSceneCaptureComplete;
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSceneEventHandling.h"
|
||||
|
||||
#include "OculusXRHMD.h"
|
||||
#include "IOculusXRSceneModule.h"
|
||||
#include "OculusXRAnchorBPFunctionLibrary.h"
|
||||
#include "OculusXRSceneDelegates.h"
|
||||
#include "OculusXRSceneEventDelegates.h"
|
||||
#include "OculusXRSceneModule.h"
|
||||
|
||||
namespace OculusXRScene
|
||||
{
|
||||
template <typename T>
|
||||
void GetEventData(ovrpEventDataBuffer& Buffer, T& OutEventData)
|
||||
{
|
||||
unsigned char* BufData = Buffer.EventData;
|
||||
BufData -= sizeof(Buffer.EventType); // Offset buffer data to get to the actual event payload
|
||||
|
||||
memcpy(&OutEventData, BufData, sizeof(T));
|
||||
}
|
||||
|
||||
void FOculusXRSceneEventHandling::OnPollEvent(ovrpEventDataBuffer* EventDataBuffer, bool& EventPollResult)
|
||||
{
|
||||
ovrpEventDataBuffer& buf = *EventDataBuffer;
|
||||
EventPollResult = true;
|
||||
|
||||
switch (buf.EventType)
|
||||
{
|
||||
case ovrpEventType_SceneCaptureComplete:
|
||||
{
|
||||
ovrpEventSceneCaptureComplete sceneCaptureComplete;
|
||||
unsigned char* bufData = buf.EventData;
|
||||
|
||||
memcpy(&sceneCaptureComplete.requestId, bufData, sizeof(sceneCaptureComplete.requestId));
|
||||
bufData += sizeof(ovrpUInt64); // move forward
|
||||
memcpy(&sceneCaptureComplete.result, bufData, sizeof(sceneCaptureComplete.result));
|
||||
|
||||
FOculusXRSceneEventDelegates::OculusSceneCaptureComplete.Broadcast(FOculusXRUInt64(sceneCaptureComplete.requestId), sceneCaptureComplete.result >= 0);
|
||||
break;
|
||||
}
|
||||
case ovrpEventType_BoundaryVisibilityChanged:
|
||||
{
|
||||
ovrpEventDataBoundaryVisibilityChanged visibilityChangedEvent;
|
||||
GetEventData(buf, visibilityChangedEvent);
|
||||
|
||||
ovrpBoundaryVisibility newVisibility = visibilityChangedEvent.BoundaryVisibility;
|
||||
EOculusXRBoundaryVisibility ueVisibility = EOculusXRBoundaryVisibility::Invalid;
|
||||
switch (newVisibility)
|
||||
{
|
||||
case ovrpBoundaryVisibility_Suppressed:
|
||||
ueVisibility = EOculusXRBoundaryVisibility::Suppressed;
|
||||
break;
|
||||
|
||||
case ovrpBoundaryVisibility_NotSuppressed:
|
||||
ueVisibility = EOculusXRBoundaryVisibility::NotSuppressed;
|
||||
break;
|
||||
|
||||
default:
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("Unknown ovrp boundary type in BoundaryVisibilityChanged event! Enum value(%d)"), newVisibility);
|
||||
}
|
||||
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT("FOculusXRSceneEventHandling - Boundary visibility changed. Visibility(%s)"), *UEnum::GetValueAsString(ueVisibility));
|
||||
|
||||
FOculusXRSceneEventDelegates::OculusBoundaryVisibilityChanged.Broadcast(ueVisibility);
|
||||
UOculusXRSceneEventDelegates* eventDelegates = GEngine->GetEngineSubsystem<UOculusXRSceneEventDelegates>();
|
||||
if (eventDelegates != nullptr)
|
||||
{
|
||||
eventDelegates->OnBoundaryVisibilityChanged.Broadcast(ueVisibility);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ovrpEventType_None:
|
||||
default:
|
||||
{
|
||||
EventPollResult = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace OculusXRScene
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
All rights reserved.
|
||||
|
||||
This source code is licensed under the license found in the
|
||||
LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
|
||||
namespace OculusXRScene
|
||||
{
|
||||
struct OCULUSXRSCENE_API FOculusXRSceneEventHandling
|
||||
{
|
||||
static void OnPollEvent(ovrpEventDataBuffer* EventDataBuffer, bool& EventPollResult);
|
||||
};
|
||||
} // namespace OculusXRScene
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSceneFunctionLibrary.h"
|
||||
|
||||
#include "Engine/GameInstance.h"
|
||||
#include "OculusXRAnchorBPFunctionLibrary.h"
|
||||
#include "OculusXRScene.h"
|
||||
#include "OculusXRSceneModule.h"
|
||||
#include "OculusXRSceneSubsystem.h"
|
||||
#include "OculusXRAnchors.h"
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "OculusXRHMD.h"
|
||||
|
||||
bool UOculusXRSceneFunctionLibrary::GetBoundaryVisibility(const UObject* WorldContext, EOculusXRBoundaryVisibility& OutVisibility)
|
||||
{
|
||||
OutVisibility = EOculusXRBoundaryVisibility::NotSuppressed;
|
||||
|
||||
check(WorldContext);
|
||||
check(WorldContext->GetWorld());
|
||||
|
||||
UOculusXRSceneSubsystem* subsystem = WorldContext->GetWorld()->GetGameInstance()->GetSubsystem<UOculusXRSceneSubsystem>();
|
||||
if (subsystem == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OutVisibility = subsystem->GetBoundaryVisibility();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UOculusXRSceneFunctionLibrary::GetRequestedBoundaryVisibility(const UObject* WorldContext, EOculusXRBoundaryVisibility& OutVisibility)
|
||||
{
|
||||
OutVisibility = EOculusXRBoundaryVisibility::NotSuppressed;
|
||||
|
||||
check(WorldContext);
|
||||
check(WorldContext->GetWorld());
|
||||
|
||||
UOculusXRSceneSubsystem* subsystem = WorldContext->GetWorld()->GetGameInstance()->GetSubsystem<UOculusXRSceneSubsystem>();
|
||||
if (subsystem == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OutVisibility = subsystem->GetRequestedBoundaryVisibility();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UOculusXRSceneFunctionLibrary::RequestBoundaryVisibility(const UObject* WorldContext, EOculusXRBoundaryVisibility Visibility)
|
||||
{
|
||||
check(WorldContext);
|
||||
check(WorldContext->GetWorld());
|
||||
|
||||
UOculusXRSceneSubsystem* subsystem = WorldContext->GetWorld()->GetGameInstance()->GetSubsystem<UOculusXRSceneSubsystem>();
|
||||
if (subsystem == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
subsystem->SetRequestedBoundaryVisibility(Visibility);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UOculusXRSceneFunctionLibrary::GetRoomLayout(FOculusXRUInt64 Space, FOculusXRRoomLayout& RoomLayoutOut, int32 MaxWallsCapacity)
|
||||
{
|
||||
if (MaxWallsCapacity <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FOculusXRUUID OutCeilingUuid;
|
||||
FOculusXRUUID OutFloorUuid;
|
||||
TArray<FOculusXRUUID> OutWallsUuid;
|
||||
|
||||
auto result = OculusXRScene::FOculusXRScene::GetRoomLayout(Space.Value, static_cast<uint32>(MaxWallsCapacity), OutCeilingUuid, OutFloorUuid, OutWallsUuid);
|
||||
auto bSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(result);
|
||||
|
||||
if (bSuccess)
|
||||
{
|
||||
RoomLayoutOut.CeilingUuid = OutCeilingUuid;
|
||||
RoomLayoutOut.FloorUuid = OutFloorUuid;
|
||||
RoomLayoutOut.WallsUuid.InsertZeroed(0, OutWallsUuid.Num());
|
||||
|
||||
for (int32 i = 0; i < OutWallsUuid.Num(); ++i)
|
||||
{
|
||||
RoomLayoutOut.WallsUuid[i] = OutWallsUuid[i];
|
||||
}
|
||||
|
||||
TArray<FOculusXRUUID> spaceUUIDs;
|
||||
EOculusXRAnchorResult::Type getContainerUUIDsResult;
|
||||
OculusXRAnchors::FOculusXRAnchors::GetSpaceContainerUUIDs(Space, spaceUUIDs, getContainerUUIDsResult);
|
||||
|
||||
if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(getContainerUUIDsResult))
|
||||
{
|
||||
RoomLayoutOut.RoomObjectUUIDs = spaceUUIDs;
|
||||
}
|
||||
}
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSceneFunctionsOVR.h"
|
||||
#include "OculusXRSceneModule.h"
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "OculusXRHMD.h"
|
||||
#include "OculusXRPluginWrapper.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "OculusXRScene"
|
||||
|
||||
namespace OculusXRScene
|
||||
{
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOVR::GetScenePlane(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize)
|
||||
{
|
||||
OutPos.X = OutPos.Y = OutPos.Z = 0.f;
|
||||
OutSize.X = OutSize.Y = OutSize.Z = 0.f;
|
||||
|
||||
ovrpRectf rect;
|
||||
const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceBoundingBox2D(&AnchorHandle, &rect);
|
||||
|
||||
if (OVRP_SUCCESS(Result))
|
||||
{
|
||||
// Convert to UE's coordinates system
|
||||
OutPos.Y = rect.Pos.x;
|
||||
OutPos.Z = rect.Pos.y;
|
||||
OutSize.Y = rect.Size.w;
|
||||
OutSize.Z = rect.Size.h;
|
||||
}
|
||||
|
||||
return static_cast<EOculusXRAnchorResult::Type>(Result);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOVR::GetSceneVolume(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize)
|
||||
{
|
||||
OutPos.X = OutPos.Y = OutPos.Z = 0.f;
|
||||
OutSize.X = OutSize.Y = OutSize.Z = 0.f;
|
||||
|
||||
ovrpBoundsf bounds;
|
||||
const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceBoundingBox3D(&AnchorHandle, &bounds);
|
||||
|
||||
if (OVRP_SUCCESS(Result))
|
||||
{
|
||||
// Convert from OpenXR's right-handed to Unreal's left-handed coordinate system.
|
||||
// OpenXR Unreal
|
||||
// | y | z
|
||||
// | |
|
||||
// z <----+ +----> x
|
||||
// / /
|
||||
// x/ y/
|
||||
//
|
||||
OutPos.X = -bounds.Pos.z;
|
||||
OutPos.Y = bounds.Pos.x;
|
||||
OutPos.Z = bounds.Pos.y;
|
||||
|
||||
// The position represents the corner of the volume which has the lowest value
|
||||
// of each axis. Since we flipped the sign of one of the axes we need to adjust
|
||||
// the position to the other side of the volume
|
||||
OutPos.X -= bounds.Size.d;
|
||||
|
||||
// We keep the size positive for all dimensions
|
||||
OutSize.X = bounds.Size.d;
|
||||
OutSize.Y = bounds.Size.w;
|
||||
OutSize.Z = bounds.Size.h;
|
||||
}
|
||||
|
||||
return static_cast<EOculusXRAnchorResult::Type>(Result);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOVR::GetSemanticClassification(uint64 AnchorHandle, TArray<FString>& OutSemanticClassifications)
|
||||
{
|
||||
OutSemanticClassifications.Empty();
|
||||
|
||||
const int32 maxByteSize = 1024;
|
||||
char labelsChars[maxByteSize];
|
||||
|
||||
ovrpSemanticLabels labels;
|
||||
labels.byteCapacityInput = maxByteSize;
|
||||
labels.labels = labelsChars;
|
||||
|
||||
const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceSemanticLabels(&AnchorHandle, &labels);
|
||||
|
||||
if (OVRP_SUCCESS(Result))
|
||||
{
|
||||
FString labelsStr(labels.byteCountOutput, labels.labels);
|
||||
labelsStr.ParseIntoArray(OutSemanticClassifications, TEXT(","));
|
||||
}
|
||||
|
||||
return static_cast<EOculusXRAnchorResult::Type>(Result);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOVR::GetBoundary2D(uint64 AnchorHandle, TArray<FVector2f>& OutVertices)
|
||||
{
|
||||
TArray<ovrpVector2f> vertices;
|
||||
|
||||
// Get the number of elements in the container
|
||||
ovrpBoundary2D boundary;
|
||||
boundary.vertexCapacityInput = 0;
|
||||
boundary.vertexCountOutput = 0;
|
||||
boundary.vertices = nullptr;
|
||||
|
||||
ovrpResult result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceBoundary2D(&AnchorHandle, &boundary);
|
||||
if (OVRP_FAILURE(result))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("Failed to get space boundary 2d %d"), result);
|
||||
return static_cast<EOculusXRAnchorResult::Type>(result);
|
||||
}
|
||||
|
||||
// Retrieve the actual array of vertices
|
||||
vertices.SetNum(boundary.vertexCountOutput);
|
||||
boundary.vertexCapacityInput = boundary.vertexCountOutput;
|
||||
boundary.vertices = vertices.GetData();
|
||||
|
||||
result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceBoundary2D(&AnchorHandle, &boundary);
|
||||
if (OVRP_FAILURE(result))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("Failed to get space boundary 2d %d"), result);
|
||||
return static_cast<EOculusXRAnchorResult::Type>(result);
|
||||
}
|
||||
|
||||
// Write out the vertices
|
||||
OutVertices.Reserve(vertices.Num());
|
||||
for (const auto& it : vertices)
|
||||
{
|
||||
OutVertices.Add(FVector2f(it.x, it.y));
|
||||
}
|
||||
|
||||
return EOculusXRAnchorResult::Success;
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOVR::RequestSceneCapture(uint64& OutRequestID)
|
||||
{
|
||||
OutRequestID = 0;
|
||||
|
||||
ovrpSceneCaptureRequest sceneCaptureRequest;
|
||||
sceneCaptureRequest.request = nullptr;
|
||||
sceneCaptureRequest.requestByteCount = 0;
|
||||
|
||||
ovrpResult result = FOculusXRHMDModule::GetPluginWrapper().RequestSceneCapture(&sceneCaptureRequest, &OutRequestID);
|
||||
|
||||
return static_cast<EOculusXRAnchorResult::Type>(result);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOVR::GetRoomLayout(uint64 AnchorHandle, const uint32 MaxWallsCapacity, FOculusXRUUID& OutCeilingUuid, FOculusXRUUID& OutFloorUuid, TArray<FOculusXRUUID>& OutWallsUuid)
|
||||
{
|
||||
ovrpRoomLayout roomLayout;
|
||||
roomLayout.wallUuidCapacityInput = 0;
|
||||
roomLayout.wallUuidCountOutput = 0;
|
||||
|
||||
// First call to get output size
|
||||
ovrpResult firstCallResult = FOculusXRHMDModule::GetPluginWrapper().GetSpaceRoomLayout(&AnchorHandle, &roomLayout);
|
||||
if (OVRP_FAILURE(firstCallResult))
|
||||
{
|
||||
return static_cast<EOculusXRAnchorResult::Type>(firstCallResult);
|
||||
}
|
||||
|
||||
// Set the input size and pointer to the uuid array
|
||||
TArray<ovrpUuid> uuids;
|
||||
uuids.InsertZeroed(0, roomLayout.wallUuidCountOutput);
|
||||
|
||||
roomLayout.wallUuidCapacityInput = roomLayout.wallUuidCountOutput;
|
||||
roomLayout.wallUuids = uuids.GetData();
|
||||
|
||||
ovrpResult secondCallResult = FOculusXRHMDModule::GetPluginWrapper().GetSpaceRoomLayout(&AnchorHandle, &roomLayout);
|
||||
if (OVRP_FAILURE(secondCallResult))
|
||||
{
|
||||
return static_cast<EOculusXRAnchorResult::Type>(secondCallResult);
|
||||
}
|
||||
|
||||
OutCeilingUuid = FOculusXRUUID(roomLayout.ceilingUuid.data);
|
||||
OutFloorUuid = FOculusXRUUID(roomLayout.floorUuid.data);
|
||||
|
||||
OutWallsUuid.Empty();
|
||||
OutWallsUuid.InsertZeroed(0, uuids.Num());
|
||||
|
||||
for (int32 i = 0; i < uuids.Num(); ++i)
|
||||
{
|
||||
OutWallsUuid[i] = FOculusXRUUID(roomLayout.wallUuids[i].data);
|
||||
}
|
||||
|
||||
return static_cast<EOculusXRAnchorResult::Type>(secondCallResult);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOVR::GetTriangleMesh(uint64 AnchorHandle, TArray<FVector>& Vertices, TArray<int32>& Triangles)
|
||||
{
|
||||
ovrpTriangleMesh OVRPMesh = { 0, 0, nullptr, 0, 0, nullptr };
|
||||
|
||||
ovrpResult countResult = FOculusXRHMDModule::GetPluginWrapper().GetSpaceTriangleMesh(&AnchorHandle, &OVRPMesh);
|
||||
if (OVRP_FAILURE(countResult))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("Failed to load TriangleMesh info - Space: %llu - Result: %d"), AnchorHandle, countResult);
|
||||
return static_cast<EOculusXRAnchorResult::Type>(countResult);
|
||||
}
|
||||
OVRPMesh.indexCapacityInput = OVRPMesh.indexCountOutput;
|
||||
OVRPMesh.vertexCapacityInput = OVRPMesh.vertexCountOutput;
|
||||
|
||||
TArray<ovrpVector3f> OVRPVertices;
|
||||
OVRPVertices.SetNum(OVRPMesh.vertexCapacityInput);
|
||||
OVRPMesh.vertices = OVRPVertices.GetData();
|
||||
Triangles.SetNum(OVRPMesh.indexCapacityInput);
|
||||
check(sizeof(TRemoveReference<decltype(Triangles)>::Type::ElementType) == sizeof(TRemovePointer<decltype(OVRPMesh.indices)>::Type));
|
||||
OVRPMesh.indices = Triangles.GetData();
|
||||
|
||||
const ovrpResult meshResult = FOculusXRHMDModule::GetPluginWrapper().GetSpaceTriangleMesh(&AnchorHandle, &OVRPMesh);
|
||||
if (OVRP_FAILURE(meshResult))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("Failed to load TriangleMesh data - AnchorHandle: %llu - Result: %d"), AnchorHandle, meshResult);
|
||||
return static_cast<EOculusXRAnchorResult::Type>(meshResult);
|
||||
}
|
||||
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("Loaded TriangleMesh data - AnchorHandle: %llu - Vertices: %d - Faces: %d"),
|
||||
AnchorHandle, OVRPMesh.vertexCapacityInput, OVRPMesh.indexCapacityInput);
|
||||
|
||||
Vertices.Empty(OVRPVertices.Num());
|
||||
Algo::Transform(OVRPVertices, Vertices, [](const auto& Vertex) { return OculusXRHMD::ToFVector(Vertex); });
|
||||
|
||||
return static_cast<EOculusXRAnchorResult::Type>(meshResult);
|
||||
}
|
||||
|
||||
// Requests to change the current boundary visibility
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOVR::RequestBoundaryVisibility(EOculusXRBoundaryVisibility NewVisibilityRequest)
|
||||
{
|
||||
ovrpBoundaryVisibility visibility = ovrpBoundaryVisibility_NotSuppressed;
|
||||
|
||||
switch (NewVisibilityRequest)
|
||||
{
|
||||
case EOculusXRBoundaryVisibility::Suppressed:
|
||||
visibility = ovrpBoundaryVisibility_Suppressed;
|
||||
break;
|
||||
case EOculusXRBoundaryVisibility::NotSuppressed:
|
||||
visibility = ovrpBoundaryVisibility_NotSuppressed;
|
||||
break;
|
||||
default:
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("RequestBoundaryVisibility -- Unknown boundary visibility value! (%d)"), static_cast<int32>(NewVisibilityRequest));
|
||||
return EOculusXRAnchorResult::Failure_InvalidParameter;
|
||||
}
|
||||
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT("RequestBoundaryVisibility -- New Visibility Requested (%s)"), *UEnum::GetValueAsString(NewVisibilityRequest));
|
||||
|
||||
auto result = FOculusXRHMDModule::GetPluginWrapper().RequestBoundaryVisibility(visibility);
|
||||
auto castedResult = static_cast<EOculusXRAnchorResult::Type>(result);
|
||||
|
||||
if (!OVRP_SUCCESS(result))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("RequestBoundaryVisibility failed -- Result(%s)"), *UEnum::GetValueAsString(castedResult));
|
||||
}
|
||||
|
||||
return castedResult;
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOVR::GetBoundaryVisibility(EOculusXRBoundaryVisibility& OutVisibility)
|
||||
{
|
||||
ovrpBoundaryVisibility visibility = {};
|
||||
auto result = FOculusXRHMDModule::GetPluginWrapper().GetBoundaryVisibility(&visibility);
|
||||
auto castedResult = static_cast<EOculusXRAnchorResult::Type>(result);
|
||||
|
||||
if (OVRP_SUCCESS(result))
|
||||
{
|
||||
switch (visibility)
|
||||
{
|
||||
case ovrpBoundaryVisibility_Suppressed:
|
||||
OutVisibility = EOculusXRBoundaryVisibility::Suppressed;
|
||||
break;
|
||||
case ovrpBoundaryVisibility_NotSuppressed:
|
||||
OutVisibility = EOculusXRBoundaryVisibility::NotSuppressed;
|
||||
break;
|
||||
default:
|
||||
OutVisibility = EOculusXRBoundaryVisibility::Invalid;
|
||||
UE_LOG(LogOculusXRScene, Error, TEXT("GetBoundaryVisibility -- Unknown boundary visibility value! Value(%d)"), visibility);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("GetBoundaryVisibility -- Failed to get boundary visibility. Result(%s)"), *UEnum::GetValueAsString(castedResult));
|
||||
}
|
||||
|
||||
return castedResult;
|
||||
}
|
||||
|
||||
} // namespace OculusXRScene
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "OculusXRSceneFunctions.h"
|
||||
|
||||
namespace OculusXRScene
|
||||
{
|
||||
struct OCULUSXRSCENE_API FOculusXRSceneFunctionsOVR : public IOculusXRSceneFunctions
|
||||
{
|
||||
virtual EOculusXRAnchorResult::Type GetScenePlane(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize) override;
|
||||
virtual EOculusXRAnchorResult::Type GetSceneVolume(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize) override;
|
||||
virtual EOculusXRAnchorResult::Type GetSemanticClassification(uint64 AnchorHandle, TArray<FString>& OutSemanticClassifications) override;
|
||||
virtual EOculusXRAnchorResult::Type GetBoundary2D(uint64 AnchorHandle, TArray<FVector2f>& OutVertices) override;
|
||||
|
||||
virtual EOculusXRAnchorResult::Type RequestSceneCapture(uint64& OutRequestID) override;
|
||||
virtual EOculusXRAnchorResult::Type GetRoomLayout(uint64 AnchorHandle, const uint32 MaxWallsCapacity, FOculusXRUUID& OutCeilingUuid, FOculusXRUUID& OutFloorUuid, TArray<FOculusXRUUID>& OutWallsUuid) override;
|
||||
virtual EOculusXRAnchorResult::Type GetTriangleMesh(uint64 AnchorHandle, TArray<FVector>& Vertices, TArray<int32>& Triangles) override;
|
||||
|
||||
// Requests to change the current boundary visibility
|
||||
virtual EOculusXRAnchorResult::Type RequestBoundaryVisibility(EOculusXRBoundaryVisibility NewVisibilityRequest) override;
|
||||
|
||||
// Gets the current boundary visibility
|
||||
virtual EOculusXRAnchorResult::Type GetBoundaryVisibility(EOculusXRBoundaryVisibility& OutVisibility) override;
|
||||
|
||||
};
|
||||
} // namespace OculusXRScene
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSceneFunctionsOpenXR.h"
|
||||
#include "OculusXRSceneModule.h"
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "OculusXRHMD.h"
|
||||
#include "OculusXRPluginWrapper.h"
|
||||
#include "OculusXRAnchorsUtil.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "OculusXRScene"
|
||||
|
||||
namespace OculusXRScene
|
||||
{
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOpenXR::GetScenePlane(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize)
|
||||
{
|
||||
auto result = FOculusXRSceneModule::Get().GetXrScene()->GetScenePlane(AnchorHandle, OutPos, OutSize);
|
||||
return OculusXRAnchors::GetResultFromXrResult(result);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOpenXR::GetSceneVolume(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize)
|
||||
{
|
||||
auto result = FOculusXRSceneModule::Get().GetXrScene()->GetSceneVolume(AnchorHandle, OutPos, OutSize);
|
||||
return OculusXRAnchors::GetResultFromXrResult(result);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOpenXR::GetSemanticClassification(uint64 AnchorHandle, TArray<FString>& OutSemanticClassifications)
|
||||
{
|
||||
auto result = FOculusXRSceneModule::Get().GetXrScene()->GetSemanticClassification(AnchorHandle, OutSemanticClassifications);
|
||||
return OculusXRAnchors::GetResultFromXrResult(result);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOpenXR::GetBoundary2D(uint64 AnchorHandle, TArray<FVector2f>& OutVertices)
|
||||
{
|
||||
auto result = FOculusXRSceneModule::Get().GetXrScene()->GetBoundary2D(AnchorHandle, OutVertices);
|
||||
return OculusXRAnchors::GetResultFromXrResult(result);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOpenXR::RequestSceneCapture(uint64& OutRequestID)
|
||||
{
|
||||
auto result = FOculusXRSceneModule::Get().GetXrScene()->RequestSceneCapture(OutRequestID);
|
||||
return OculusXRAnchors::GetResultFromXrResult(result);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOpenXR::GetRoomLayout(uint64 AnchorHandle, const uint32 MaxWallsCapacity, FOculusXRUUID& OutCeilingUuid, FOculusXRUUID& OutFloorUuid, TArray<FOculusXRUUID>& OutWallsUuid)
|
||||
{
|
||||
auto result = FOculusXRSceneModule::Get().GetXrScene()->GetRoomLayout(AnchorHandle, MaxWallsCapacity, OutCeilingUuid, OutFloorUuid, OutWallsUuid);
|
||||
return OculusXRAnchors::GetResultFromXrResult(result);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOpenXR::GetTriangleMesh(uint64 AnchorHandle, TArray<FVector>& Vertices, TArray<int32>& Triangles)
|
||||
{
|
||||
auto result = FOculusXRSceneModule::Get().GetXrScene()->GetTriangleMesh(AnchorHandle, Vertices, Triangles);
|
||||
return OculusXRAnchors::GetResultFromXrResult(result);
|
||||
}
|
||||
|
||||
// Requests to change the current boundary visibility
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOpenXR::RequestBoundaryVisibility(EOculusXRBoundaryVisibility NewVisibilityRequest)
|
||||
{
|
||||
auto result = FOculusXRSceneModule::Get().GetXrScene()->RequestBoundaryVisibility(NewVisibilityRequest);
|
||||
return OculusXRAnchors::GetResultFromXrResult(result);
|
||||
}
|
||||
|
||||
EOculusXRAnchorResult::Type FOculusXRSceneFunctionsOpenXR::GetBoundaryVisibility(EOculusXRBoundaryVisibility& OutVisibility)
|
||||
{
|
||||
auto result = FOculusXRSceneModule::Get().GetXrScene()->GetBoundaryVisibility(OutVisibility);
|
||||
return OculusXRAnchors::GetResultFromXrResult(result);
|
||||
}
|
||||
|
||||
} // namespace OculusXRScene
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "OculusXRSceneFunctions.h"
|
||||
|
||||
namespace OculusXRScene
|
||||
{
|
||||
struct OCULUSXRSCENE_API FOculusXRSceneFunctionsOpenXR : public IOculusXRSceneFunctions
|
||||
{
|
||||
virtual EOculusXRAnchorResult::Type GetScenePlane(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize) override;
|
||||
virtual EOculusXRAnchorResult::Type GetSceneVolume(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize) override;
|
||||
virtual EOculusXRAnchorResult::Type GetSemanticClassification(uint64 AnchorHandle, TArray<FString>& OutSemanticClassifications) override;
|
||||
virtual EOculusXRAnchorResult::Type GetBoundary2D(uint64 AnchorHandle, TArray<FVector2f>& OutVertices) override;
|
||||
|
||||
virtual EOculusXRAnchorResult::Type RequestSceneCapture(uint64& OutRequestID) override;
|
||||
virtual EOculusXRAnchorResult::Type GetRoomLayout(uint64 AnchorHandle, const uint32 MaxWallsCapacity, FOculusXRUUID& OutCeilingUuid, FOculusXRUUID& OutFloorUuid, TArray<FOculusXRUUID>& OutWallsUuid) override;
|
||||
virtual EOculusXRAnchorResult::Type GetTriangleMesh(uint64 AnchorHandle, TArray<FVector>& Vertices, TArray<int32>& Triangles) override;
|
||||
|
||||
// Requests to change the current boundary visibility
|
||||
virtual EOculusXRAnchorResult::Type RequestBoundaryVisibility(EOculusXRBoundaryVisibility NewVisibilityRequest) override;
|
||||
|
||||
// Gets the current boundary visibility
|
||||
virtual EOculusXRAnchorResult::Type GetBoundaryVisibility(EOculusXRBoundaryVisibility& OutVisibility) override;
|
||||
|
||||
};
|
||||
} // namespace OculusXRScene
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSceneGlobalMeshComponent.h"
|
||||
#include "OculusXRSceneModule.h"
|
||||
#include "OculusXRRoomLayoutManagerComponent.h"
|
||||
#include "ProceduralMeshComponent.h"
|
||||
#include "Engine/World.h"
|
||||
#include "GameFramework/WorldSettings.h"
|
||||
#include "Materials/MaterialInterface.h"
|
||||
|
||||
const FString UOculusXRSceneGlobalMeshComponent::GlobalMeshSemanticLabel = TEXT("GLOBAL_MESH");
|
||||
|
||||
UOculusXRSceneGlobalMeshComponent::UOculusXRSceneGlobalMeshComponent(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
}
|
||||
|
||||
void UOculusXRSceneGlobalMeshComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||
{
|
||||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||
}
|
||||
|
||||
bool UOculusXRSceneGlobalMeshComponent::HasCollision() const
|
||||
{
|
||||
return Collision;
|
||||
}
|
||||
|
||||
bool UOculusXRSceneGlobalMeshComponent::IsVisible() const
|
||||
{
|
||||
return Visible;
|
||||
}
|
||||
|
||||
UClass* UOculusXRSceneGlobalMeshComponent::GetAnchorComponentClass() const
|
||||
{
|
||||
UClass* sceneAnchorComponentInstanceClass = SceneAnchorComponent ? SceneAnchorComponent.LoadSynchronous() : nullptr;
|
||||
return sceneAnchorComponentInstanceClass;
|
||||
}
|
||||
|
||||
void UOculusXRSceneGlobalMeshComponent::CreateMeshComponent(const FOculusXRUInt64& Space, AActor* GlobalMeshAnchor, const UOculusXRRoomLayoutManagerComponent* RoomLayoutManagerComponent) const
|
||||
{
|
||||
bool hasCollision = HasCollision();
|
||||
UProceduralMeshComponent* proceduralMeshComponent = NewObject<UProceduralMeshComponent>(GlobalMeshAnchor);
|
||||
proceduralMeshComponent->RegisterComponent();
|
||||
|
||||
bool bLoaded = RoomLayoutManagerComponent->LoadTriangleMesh(Space.Value, proceduralMeshComponent, hasCollision);
|
||||
ensure(bLoaded);
|
||||
UMaterialInterface* refMaterial = Material;
|
||||
if (refMaterial != nullptr)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("GLOBAL MESH Set Material %s"), *refMaterial->GetName());
|
||||
proceduralMeshComponent->SetMaterial(0, refMaterial);
|
||||
}
|
||||
if (hasCollision)
|
||||
{
|
||||
FName refCollisionProfile = CollisionProfileName.Name;
|
||||
proceduralMeshComponent->SetCollisionProfileName(refCollisionProfile);
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("GLOBAL MESH Set Collision Profile %s"), *refCollisionProfile.ToString());
|
||||
}
|
||||
GlobalMeshAnchor->AddOwnedComponent(proceduralMeshComponent);
|
||||
proceduralMeshComponent->AttachToComponent(GlobalMeshAnchor->GetRootComponent(), FAttachmentTransformRules::KeepWorldTransform);
|
||||
proceduralMeshComponent->SetRelativeLocation(FVector::ZeroVector, false, nullptr, ETeleportType::ResetPhysics);
|
||||
|
||||
proceduralMeshComponent->SetVisibility(IsVisible());
|
||||
|
||||
const float worldToMeters = GetWorld()->GetWorldSettings()->WorldToMeters;
|
||||
proceduralMeshComponent->SetRelativeScale3D(FVector(worldToMeters, worldToMeters, worldToMeters));
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSceneLatentActions.h"
|
||||
#include "OculusXRHMD.h"
|
||||
#include "OculusXRAnchorBPFunctionLibrary.h"
|
||||
#include "OculusXRSceneModule.h"
|
||||
#include "OculusXRSceneDelegates.h"
|
||||
#include "OculusXRScene.h"
|
||||
|
||||
UOculusXRAsyncAction_LaunchCaptureFlow* UOculusXRAsyncAction_LaunchCaptureFlow::LaunchCaptureFlowAsync(const UObject* WorldContext)
|
||||
{
|
||||
UWorld* World = GEngine->GetWorldFromContextObject(WorldContext, EGetWorldErrorMode::ReturnNull);
|
||||
if (!ensureAlwaysMsgf(IsValid(WorldContext), TEXT("World Context was not valid.")))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto NewAction = NewObject<UOculusXRAsyncAction_LaunchCaptureFlow>();
|
||||
NewAction->RegisterWithGameInstance(World->GetGameInstance());
|
||||
return NewAction;
|
||||
}
|
||||
|
||||
void UOculusXRAsyncAction_LaunchCaptureFlow::Activate()
|
||||
{
|
||||
RequestId = 0;
|
||||
FOculusXRSceneEventDelegates::OculusSceneCaptureComplete.AddUObject(this, &UOculusXRAsyncAction_LaunchCaptureFlow::OnCaptureFinish);
|
||||
auto result = OculusXRScene::FOculusXRScene::RequestSceneCapture(RequestId);
|
||||
if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(result))
|
||||
{
|
||||
FOculusXRSceneEventDelegates::OculusSceneCaptureComplete.RemoveAll(this);
|
||||
Failure.Broadcast();
|
||||
}
|
||||
}
|
||||
|
||||
void UOculusXRAsyncAction_LaunchCaptureFlow::OnCaptureFinish(FOculusXRUInt64 Id, bool bSuccess)
|
||||
{
|
||||
if (RequestId != Id.GetValue())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("Incoming request id (%llu) doesn't match expected request id (%llu). Ignoring request."), Id.GetValue(), RequestId);
|
||||
return;
|
||||
}
|
||||
|
||||
FOculusXRSceneEventDelegates::OculusSceneCaptureComplete.RemoveAll(this);
|
||||
Success.Broadcast();
|
||||
SetReadyToDestroy();
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRSceneModule.h"
|
||||
|
||||
#if OCULUS_SCENE_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRHMDModule.h"
|
||||
|
||||
#include "OculusXRHMD.h"
|
||||
#include "OculusXRSceneEventHandling.h"
|
||||
#include "OculusXRSceneComponents.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogOculusXRScene);
|
||||
|
||||
#define LOCTEXT_NAMESPACE "OculusXRScene"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FOculusXRSceneModule
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void FOculusXRSceneModule::StartupModule()
|
||||
{
|
||||
SceneXR = MakeShareable(new XRScene::FSceneXR());
|
||||
SceneXR->RegisterAsOpenXRExtension();
|
||||
|
||||
FCoreDelegates::OnPostEngineInit.AddRaw(this, &FOculusXRSceneModule::OnPostEngineInit);
|
||||
|
||||
auto anchorsModule = FModuleManager::GetModulePtr<IOculusXRAnchorsModule>("OculusXRAnchors");
|
||||
anchorsModule->AddCreateAnchorComponentInterface(this);
|
||||
}
|
||||
|
||||
void FOculusXRSceneModule::ShutdownModule()
|
||||
{
|
||||
auto anchorsModule = FModuleManager::GetModulePtr<IOculusXRAnchorsModule>("OculusXRAnchors");
|
||||
anchorsModule->RemoveCreateAnchorComponentInterface(this);
|
||||
}
|
||||
|
||||
void FOculusXRSceneModule::OnPostEngineInit()
|
||||
{
|
||||
if (IsRunningCommandlet())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GEngine)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OculusXRHMD::FOculusXRHMD* HMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (!HMD)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("Unable to retrieve OculusXRHMD, cannot add event polling delegates."));
|
||||
return;
|
||||
}
|
||||
|
||||
HMD->AddEventPollingDelegate(OculusXRHMD::FOculusXRHMDEventPollingDelegate::CreateStatic(&OculusXRScene::FOculusXRSceneEventHandling::OnPollEvent));
|
||||
}
|
||||
|
||||
UOculusXRBaseAnchorComponent* FOculusXRSceneModule::TryCreateAnchorComponent(uint64 AnchorHandle, EOculusXRSpaceComponentType Type, UObject* Outer)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case EOculusXRSpaceComponentType::ScenePlane:
|
||||
return UOculusXRBaseAnchorComponent::FromSpace<UOculusXRPlaneAnchorComponent>(AnchorHandle, Outer);
|
||||
case EOculusXRSpaceComponentType::SceneVolume:
|
||||
return UOculusXRBaseAnchorComponent::FromSpace<UOculusXRVolumeAnchorComponent>(AnchorHandle, Outer);
|
||||
case EOculusXRSpaceComponentType::SemanticClassification:
|
||||
return UOculusXRBaseAnchorComponent::FromSpace<UOculusXRSemanticClassificationAnchorComponent>(AnchorHandle, Outer);
|
||||
case EOculusXRSpaceComponentType::RoomLayout:
|
||||
return UOculusXRBaseAnchorComponent::FromSpace<UOculusXRRoomLayoutAnchorComponent>(AnchorHandle, Outer);
|
||||
case EOculusXRSpaceComponentType::TriangleMesh:
|
||||
return UOculusXRBaseAnchorComponent::FromSpace<UOculusXRTriangleMeshAnchorComponent>(AnchorHandle, Outer);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OCULUS_SCENE_SUPPORTED_PLATFORMS
|
||||
|
||||
IMPLEMENT_MODULE(FOculusXRSceneModule, OculusXRScene)
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,54 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "IOculusXRSceneModule.h"
|
||||
#include "OculusXRAnchorsModule.h"
|
||||
#include "openxr/OculusXRSceneXR.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "OculusXRScene"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FOculusXRSceneModule
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogOculusXRScene, Log, All);
|
||||
|
||||
typedef TSharedPtr<XRScene::FSceneXR, ESPMode::ThreadSafe> FSceneXRPtr;
|
||||
|
||||
#if OCULUS_SCENE_SUPPORTED_PLATFORMS
|
||||
|
||||
class FOculusXRSceneModule : public IOculusXRSceneModule, public IOculusXRCreateAnchorComponent
|
||||
{
|
||||
public:
|
||||
static inline FOculusXRSceneModule& Get()
|
||||
{
|
||||
return FModuleManager::LoadModuleChecked<FOculusXRSceneModule>("OculusXRScene");
|
||||
}
|
||||
|
||||
virtual ~FOculusXRSceneModule() = default;
|
||||
|
||||
// IModuleInterface interface
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
|
||||
void OnPostEngineInit();
|
||||
|
||||
// IOculusXRCreateAnchorComponent
|
||||
virtual UOculusXRBaseAnchorComponent* TryCreateAnchorComponent(uint64 AnchorHandle, EOculusXRSpaceComponentType Type, UObject* Outer) override;
|
||||
|
||||
FSceneXRPtr GetXrScene() { return SceneXR; }
|
||||
|
||||
private:
|
||||
FSceneXRPtr SceneXR;
|
||||
};
|
||||
|
||||
#else // OCULUS_SCENE_SUPPORTED_PLATFORMS
|
||||
|
||||
class FOculusXRSceneModule : public FDefaultModuleImpl
|
||||
{
|
||||
};
|
||||
|
||||
#endif // OCULUS_SCENE_SUPPORTED_PLATFORMS
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,117 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSceneSubsystem.h"
|
||||
#include "OculusXRSceneTypes.h"
|
||||
#include "OculusXRScene.h"
|
||||
#include "IOculusXRSceneModule.h"
|
||||
#include "OculusXRSceneDelegates.h"
|
||||
#include "OculusXRAnchorBPFunctionLibrary.h"
|
||||
#include "OculusXRHMD.h"
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
#include "OculusXRSceneModule.h"
|
||||
#include "OculusXRPassthroughModule.h"
|
||||
#include "OculusXRPassthroughXR.h"
|
||||
|
||||
UOculusXRSceneSubsystem::UOculusXRSceneSubsystem()
|
||||
: requestedVisibilityState_(EOculusXRBoundaryVisibility::NotSuppressed)
|
||||
, bInitialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool UOculusXRSceneSubsystem::ShouldCreateSubsystem(UObject* Outer) const
|
||||
{
|
||||
return GetDefault<UOculusXRHMDRuntimeSettings>()->bBoundaryVisibilitySupportEnabled && GetDefault<UOculusXRHMDRuntimeSettings>()->bInsightPassthroughEnabled;
|
||||
}
|
||||
|
||||
void UOculusXRSceneSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
||||
{
|
||||
bool enabled = GetDefault<UOculusXRHMDRuntimeSettings>()->bBoundaryVisibilitySupportEnabled;
|
||||
bool suppressed = GetDefault<UOculusXRHMDRuntimeSettings>()->bDefaultBoundaryVisibilitySuppressed;
|
||||
|
||||
// This is the desired state
|
||||
bool isBoundaryNotSuppressed = enabled && !suppressed;
|
||||
requestedVisibilityState_ = isBoundaryNotSuppressed ? EOculusXRBoundaryVisibility::NotSuppressed : EOculusXRBoundaryVisibility::Suppressed;
|
||||
visChangedEventHandle_ = FOculusXRSceneEventDelegates::OculusBoundaryVisibilityChanged.AddUObject(this, &UOculusXRSceneSubsystem::OnBoundaryVisibilityChanged);
|
||||
|
||||
bInitialized = true;
|
||||
}
|
||||
|
||||
void UOculusXRSceneSubsystem::Deinitialize()
|
||||
{
|
||||
FOculusXRSceneEventDelegates::OculusBoundaryVisibilityChanged.Remove(visChangedEventHandle_);
|
||||
bInitialized = false;
|
||||
}
|
||||
|
||||
ETickableTickType UOculusXRSceneSubsystem::GetTickableTickType() const
|
||||
{
|
||||
return IsTemplate() ? ETickableTickType::Never : FTickableGameObject::GetTickableTickType();
|
||||
}
|
||||
|
||||
bool UOculusXRSceneSubsystem::IsAllowedToTick() const
|
||||
{
|
||||
return !IsTemplate() && bInitialized;
|
||||
}
|
||||
|
||||
void UOculusXRSceneSubsystem::Tick(float DeltaTime)
|
||||
{
|
||||
UpdateBoundary();
|
||||
}
|
||||
|
||||
EOculusXRBoundaryVisibility UOculusXRSceneSubsystem::GetBoundaryVisibility()
|
||||
{
|
||||
EOculusXRBoundaryVisibility boundaryVisibility = {};
|
||||
OculusXRScene::FOculusXRScene::GetBoundaryVisibility(boundaryVisibility);
|
||||
return boundaryVisibility;
|
||||
}
|
||||
|
||||
EOculusXRBoundaryVisibility UOculusXRSceneSubsystem::GetRequestedBoundaryVisibility()
|
||||
{
|
||||
return requestedVisibilityState_;
|
||||
}
|
||||
|
||||
void UOculusXRSceneSubsystem::SetRequestedBoundaryVisibility(EOculusXRBoundaryVisibility Visibility)
|
||||
{
|
||||
requestedVisibilityState_ = Visibility;
|
||||
}
|
||||
|
||||
void UOculusXRSceneSubsystem::OnBoundaryVisibilityChanged(EOculusXRBoundaryVisibility visibility)
|
||||
{
|
||||
// Do nothing on event
|
||||
}
|
||||
|
||||
void UOculusXRSceneSubsystem::UpdateBoundary()
|
||||
{
|
||||
// If the state is the same, skip
|
||||
auto currentVisibilityState = GetBoundaryVisibility();
|
||||
if (currentVisibilityState == requestedVisibilityState_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Log only if the value != the requested state, else we pollute the log (per-frame call)
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT("GetBoundaryVisibility -- Visibility(%s)"), *UEnum::GetValueAsString(currentVisibilityState));
|
||||
|
||||
// TODO: This should probably be part of the passthrough API
|
||||
const FName SystemName(TEXT("OpenXR"));
|
||||
const bool IsOpenXR = GEngine->XRSystem.IsValid() && (GEngine->XRSystem->GetSystemName() == SystemName);
|
||||
if (OculusXRHMD::FOculusXRHMD::GetOculusXRHMD() != nullptr)
|
||||
{
|
||||
// If passthrough is not enabled or initialized, skip
|
||||
auto result = FOculusXRHMDModule::GetPluginWrapper().GetInsightPassthroughInitializationState();
|
||||
bool passthroughInitializedOrPending = (result >= 0);
|
||||
bool passthroughEnabled = GetDefault<UOculusXRHMDRuntimeSettings>()->bInsightPassthroughEnabled;
|
||||
if (!passthroughEnabled || !passthroughInitializedOrPending)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (IsOpenXR)
|
||||
{
|
||||
if (!FOculusXRPassthroughModule::Get().GetPassthroughExtensionPlugin().Pin()->IsPassthroughEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
OculusXRScene::FOculusXRScene::RequestBoundaryVisibility(requestedVisibilityState_);
|
||||
}
|
||||
@@ -0,0 +1,551 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSceneXR.h"
|
||||
#include "OpenXRCore.h"
|
||||
#include "OpenXRHMD.h"
|
||||
#include "IOpenXRHMDModule.h"
|
||||
#include "OpenXR/OculusXROpenXRUtilities.h"
|
||||
#include "OculusXRSceneModule.h"
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "OculusXRSceneDelegates.h"
|
||||
#include "OculusXRAnchorsUtil.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "OculusXRScene"
|
||||
|
||||
namespace XRScene
|
||||
{
|
||||
PFN_xrGetSpaceBoundingBox2DFB xrGetSpaceBoundingBox2DFB = nullptr;
|
||||
PFN_xrGetSpaceBoundingBox3DFB xrGetSpaceBoundingBox3DFB = nullptr;
|
||||
PFN_xrGetSpaceBoundary2DFB xrGetSpaceBoundary2DFB = nullptr;
|
||||
PFN_xrGetSpaceSemanticLabelsFB xrGetSpaceSemanticLabelsFB = nullptr;
|
||||
PFN_xrRequestSceneCaptureFB xrRequestSceneCaptureFB = nullptr;
|
||||
PFN_xrGetSpaceRoomLayoutFB xrGetSpaceRoomLayoutFB = nullptr;
|
||||
PFN_xrGetSpaceTriangleMeshMETA xrGetSpaceTriangleMeshMETA = nullptr;
|
||||
PFN_xrRequestBoundaryVisibilityMETA xrRequestBoundaryVisibilityMETA = nullptr;
|
||||
|
||||
FSceneXR::FSceneXR()
|
||||
: bExtSceneEnabled(false)
|
||||
, bExtSceneCaptureEnabled(false)
|
||||
, bExtBoundaryVisibilityEnabled(false)
|
||||
, bExtSpatialEntityMeshEnabled(false)
|
||||
, LastBoundaryVisibility(XR_BOUNDARY_VISIBILITY_MAX_ENUM_META)
|
||||
, OpenXRHMD(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
FSceneXR::~FSceneXR()
|
||||
{
|
||||
}
|
||||
|
||||
void FSceneXR::RegisterAsOpenXRExtension()
|
||||
{
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
// Feature not enabled on Marketplace build. Currently only for the meta fork
|
||||
RegisterOpenXRExtensionModularFeature();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FSceneXR::GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions)
|
||||
{
|
||||
OutExtensions.Add(XR_FB_SCENE_EXTENSION_NAME);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FSceneXR::GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions)
|
||||
{
|
||||
OutExtensions.Add(XR_FB_SCENE_CAPTURE_EXTENSION_NAME);
|
||||
OutExtensions.Add(XR_META_SPATIAL_ENTITY_MESH_EXTENSION_NAME);
|
||||
OutExtensions.Add(XR_META_BOUNDARY_VISIBILITY_EXTENSION_NAME);
|
||||
return true;
|
||||
}
|
||||
|
||||
const void* FSceneXR::OnCreateInstance(class IOpenXRHMDModule* InModule, const void* InNext)
|
||||
{
|
||||
if (InModule != nullptr)
|
||||
{
|
||||
bExtSceneEnabled = InModule->IsExtensionEnabled(XR_FB_SCENE_EXTENSION_NAME);
|
||||
bExtSceneCaptureEnabled = InModule->IsExtensionEnabled(XR_FB_SCENE_CAPTURE_EXTENSION_NAME);
|
||||
bExtBoundaryVisibilityEnabled = InModule->IsExtensionEnabled(XR_META_BOUNDARY_VISIBILITY_EXTENSION_NAME);
|
||||
bExtSpatialEntityMeshEnabled = InModule->IsExtensionEnabled(XR_META_SPATIAL_ENTITY_MESH_EXTENSION_NAME);
|
||||
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT("[SCENE] Extensions available"));
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT(" Scene: %hs"), bExtSceneEnabled ? "ENABLED" : "DISABLED");
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT(" Scene Capture: %hs"), bExtSceneCaptureEnabled ? "ENABLED" : "DISABLED");
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT(" Boundary: %hs"), bExtBoundaryVisibilityEnabled ? "ENABLED" : "DISABLED");
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT(" Mesh: %hs"), bExtSpatialEntityMeshEnabled ? "ENABLED" : "DISABLED");
|
||||
}
|
||||
|
||||
return InNext;
|
||||
}
|
||||
|
||||
const void* FSceneXR::OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext)
|
||||
{
|
||||
InitOpenXRFunctions(InInstance);
|
||||
|
||||
OpenXRHMD = (FOpenXRHMD*)GEngine->XRSystem.Get();
|
||||
|
||||
return InNext;
|
||||
}
|
||||
|
||||
void FSceneXR::OnDestroySession(XrSession InSession)
|
||||
{
|
||||
OpenXRHMD = nullptr;
|
||||
}
|
||||
|
||||
void FSceneXR::OnEvent(XrSession InSession, const XrEventDataBaseHeader* InHeader)
|
||||
{
|
||||
if (OpenXRHMD == nullptr)
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT("[FSceneXR::OnEvent] Receieved event but no HMD was present."));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (InHeader->type)
|
||||
{
|
||||
case XR_TYPE_EVENT_DATA_BOUNDARY_VISIBILITY_CHANGED_META:
|
||||
{
|
||||
if (IsBoundaryVisibilityExtensionSupported())
|
||||
{
|
||||
const XrEventDataBoundaryVisibilityChangedMETA* const event =
|
||||
reinterpret_cast<const XrEventDataBoundaryVisibilityChangedMETA*>(InHeader);
|
||||
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("[FSceneXR::OnEvent] XrEventDataBoundaryVisibilityChangedMETA"));
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT(" Visibility: %hs"), (event->boundaryVisibility == XR_BOUNDARY_VISIBILITY_SUPPRESSED_META) ? "SUPPRESSED" : "NOT SUPPRESSED");
|
||||
|
||||
FOculusXRSceneEventDelegates::OculusBoundaryVisibilityChanged.Broadcast(event->boundaryVisibility == XR_BOUNDARY_VISIBILITY_SUPPRESSED_META ? EOculusXRBoundaryVisibility::Suppressed : EOculusXRBoundaryVisibility::NotSuppressed);
|
||||
|
||||
LastBoundaryVisibility = event->boundaryVisibility;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XR_TYPE_EVENT_DATA_SCENE_CAPTURE_COMPLETE_FB:
|
||||
{
|
||||
if (IsSceneCaptureExtensionSupported())
|
||||
{
|
||||
const XrEventDataSceneCaptureCompleteFB* const event =
|
||||
reinterpret_cast<const XrEventDataSceneCaptureCompleteFB*>(InHeader);
|
||||
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT("[FSceneXR::OnEvent] XrEventDataSceneCaptureCompleteFB"));
|
||||
UE_LOG(LogOculusXRScene, Verbose, TEXT(" Result: d"), event->result);
|
||||
|
||||
FOculusXRSceneEventDelegates::OculusSceneCaptureComplete.Broadcast(event->result, XR_SUCCEEDED(event->result));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XrResult FSceneXR::GetScenePlane(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize)
|
||||
{
|
||||
if (!OpenXRHMD || !OpenXRHMD->GetInstance() || !OpenXRHMD->GetSession())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetScenePlane] XR state is invalid."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
if (!IsSceneExtensionSupported())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetScenePlane] Scene extension is unsupported."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
XrRect2Df rect;
|
||||
auto result = xrGetSpaceBoundingBox2DFB(OpenXRHMD->GetSession(), (XrSpace)AnchorHandle, &rect);
|
||||
if (XR_FAILED(result))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetScenePlane] Get space bounding box 2D failed. Result: %d"), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Convert to UE's coordinates system
|
||||
OutPos.X = 0;
|
||||
OutPos.Y = rect.offset.x;
|
||||
OutPos.Z = rect.offset.y;
|
||||
OutSize.X = 0;
|
||||
OutSize.Y = rect.extent.width;
|
||||
OutSize.Z = rect.extent.height;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
XrResult FSceneXR::GetSceneVolume(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize)
|
||||
{
|
||||
if (!OpenXRHMD || !OpenXRHMD->GetInstance() || !OpenXRHMD->GetSession())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetSceneVolume] XR state is invalid."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
if (!IsSceneExtensionSupported())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetSceneVolume] Scene extension is unsupported."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
XrRect3DfFB rect;
|
||||
auto result = xrGetSpaceBoundingBox3DFB(OpenXRHMD->GetSession(), (XrSpace)AnchorHandle, &rect);
|
||||
if (XR_FAILED(result))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetSceneVolume] Get space bounding box 3D failed. Result: %d"), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Convert from OpenXR's right-handed to Unreal's left-handed coordinate system.
|
||||
// OpenXR Unreal
|
||||
// | y | z
|
||||
// | |
|
||||
// z <----+ +----> x
|
||||
// / /
|
||||
// x/ y/
|
||||
//
|
||||
OutPos.X = -rect.offset.z;
|
||||
OutPos.Y = rect.offset.x;
|
||||
OutPos.Z = rect.offset.y;
|
||||
|
||||
// The position represents the corner of the volume which has the lowest value
|
||||
// of each axis. Since we flipped the sign of one of the axes we need to adjust
|
||||
// the position to the other side of the volume
|
||||
OutPos.X -= rect.extent.depth;
|
||||
|
||||
// We keep the size positive for all dimensions
|
||||
OutSize.X = rect.extent.depth;
|
||||
OutSize.Y = rect.extent.width;
|
||||
OutSize.Z = rect.extent.height;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
XrResult FSceneXR::GetBoundary2D(uint64 AnchorHandle, TArray<FVector2f>& OutVertices)
|
||||
{
|
||||
if (!OpenXRHMD || !OpenXRHMD->GetInstance() || !OpenXRHMD->GetSession())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetBoundary2D] XR state is invalid."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
if (!IsSceneExtensionSupported())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetBoundary2D] Scene extension is unsupported."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
XrBoundary2DFB boundary{ XR_TYPE_BOUNDARY_2D_FB, nullptr };
|
||||
boundary.vertexCapacityInput = 0;
|
||||
boundary.vertexCountOutput = 0;
|
||||
boundary.vertices = nullptr;
|
||||
|
||||
auto getCountResult = xrGetSpaceBoundary2DFB(OpenXRHMD->GetSession(), (XrSpace)AnchorHandle, &boundary);
|
||||
if (XR_FAILED(getCountResult))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetBoundary2D] Get space boundary 2D vertex count failed. Result: %d"), getCountResult);
|
||||
return getCountResult;
|
||||
}
|
||||
|
||||
TArray<XrVector2f> vertices;
|
||||
vertices.SetNum(boundary.vertexCountOutput);
|
||||
boundary.vertexCapacityInput = boundary.vertexCountOutput;
|
||||
boundary.vertices = vertices.GetData();
|
||||
|
||||
auto getVerticesResult = xrGetSpaceBoundary2DFB(OpenXRHMD->GetSession(), (XrSpace)AnchorHandle, &boundary);
|
||||
if (XR_FAILED(getVerticesResult))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetBoundary2D] Get space boundary 2D vertices failed. Result: %d"), getVerticesResult);
|
||||
return getVerticesResult;
|
||||
}
|
||||
|
||||
OutVertices.Reserve(vertices.Num());
|
||||
for (auto& it : vertices)
|
||||
{
|
||||
OutVertices.Add(FVector2f(it.x, it.y));
|
||||
}
|
||||
|
||||
return getVerticesResult;
|
||||
}
|
||||
|
||||
XrResult FSceneXR::GetSemanticClassification(uint64 AnchorHandle, TArray<FString>& OutSemanticClassifications)
|
||||
{
|
||||
if (!OpenXRHMD || !OpenXRHMD->GetInstance() || !OpenXRHMD->GetSession())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetSemanticClassification] XR state is invalid."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
if (!IsSceneExtensionSupported())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetSemanticClassification] Scene extension is unsupported."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
static const char* recognizedLabels = "DESK,COUCH,FLOOR,CEILING,WALL_FACE,WINDOW_FRAME,DOOR_FRAME,STORAGE,BED,SCREEN,LAMP,PLANT,OTHER,TABLE,WALL_ART,INVISIBLE_WALL_FACE,GLOBAL_MESH"
|
||||
;
|
||||
|
||||
const XrSemanticLabelsSupportInfoFB semanticLabelsSupportInfo = {
|
||||
XR_TYPE_SEMANTIC_LABELS_SUPPORT_INFO_FB,
|
||||
nullptr,
|
||||
XR_SEMANTIC_LABELS_SUPPORT_ACCEPT_DESK_TO_TABLE_MIGRATION_BIT_FB | XR_SEMANTIC_LABELS_SUPPORT_ACCEPT_INVISIBLE_WALL_FACE_BIT_FB,
|
||||
recognizedLabels
|
||||
};
|
||||
|
||||
XrSemanticLabelsFB xrLabels{ XR_TYPE_SEMANTIC_LABELS_FB, &semanticLabelsSupportInfo };
|
||||
xrLabels.bufferCountOutput = 0;
|
||||
xrLabels.bufferCapacityInput = 0;
|
||||
xrLabels.buffer = nullptr;
|
||||
|
||||
XrResult result = xrGetSpaceSemanticLabelsFB(OpenXRHMD->GetSession(), (XrSpace)AnchorHandle, &xrLabels);
|
||||
if (XR_FAILED(result))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetSemanticClassification] Get semantic label buffer size failed. Result: %d"), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
TArray<char> buffer;
|
||||
buffer.SetNum(xrLabels.bufferCountOutput);
|
||||
xrLabels.bufferCapacityInput = xrLabels.bufferCountOutput;
|
||||
xrLabels.buffer = buffer.GetData();
|
||||
|
||||
result = xrGetSpaceSemanticLabelsFB(OpenXRHMD->GetSession(), (XrSpace)AnchorHandle, &xrLabels);
|
||||
if (XR_FAILED(result))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetSemanticClassification] Get semantic label buffer failed. Result: %d"), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
FString labelsStr(xrLabels.bufferCountOutput, xrLabels.buffer);
|
||||
labelsStr.ParseIntoArray(OutSemanticClassifications, TEXT(","));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
XrResult FSceneXR::RequestSceneCapture(uint64& OutRequestID)
|
||||
{
|
||||
if (!OpenXRHMD || !OpenXRHMD->GetInstance() || !OpenXRHMD->GetSession())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[RequestSceneCapture] XR state is invalid."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
if (!IsSceneCaptureExtensionSupported())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[RequestSceneCapture] Scene capture extension is unsupported."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
XrSceneCaptureRequestInfoFB info{ XR_TYPE_SCENE_CAPTURE_REQUEST_INFO_FB, nullptr };
|
||||
info.request = nullptr;
|
||||
info.requestByteCount = 0;
|
||||
|
||||
auto result = xrRequestSceneCaptureFB(OpenXRHMD->GetSession(), &info, (XrAsyncRequestIdFB*)&OutRequestID);
|
||||
if (XR_FAILED(result))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[RequestSceneCapture] Get scene capture failed. Result: %d"), result);
|
||||
}
|
||||
|
||||
UE_LOG(LogOculusXRScene, Log, TEXT("[RequestSceneCapture] Started scene capture: RequestID (%llu)"), OutRequestID);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
XrResult FSceneXR::GetRoomLayout(uint64 AnchorHandle, const uint32 MaxWallsCapacity, FOculusXRUUID& OutCeilingUuid, FOculusXRUUID& OutFloorUuid, TArray<FOculusXRUUID>& OutWallsUuid)
|
||||
{
|
||||
if (!OpenXRHMD || !OpenXRHMD->GetInstance() || !OpenXRHMD->GetSession())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetRoomLayout] XR state is invalid."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
if (!IsSceneExtensionSupported())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetRoomLayout] Scene extension is unsupported."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
XrRoomLayoutFB roomLayout{ XR_TYPE_ROOM_LAYOUT_FB, nullptr };
|
||||
roomLayout.wallUuidCapacityInput = 0;
|
||||
roomLayout.wallUuidCountOutput = 0;
|
||||
roomLayout.wallUuids = nullptr;
|
||||
|
||||
auto getWallsResult = xrGetSpaceRoomLayoutFB(OpenXRHMD->GetSession(), (XrSpace)AnchorHandle, &roomLayout);
|
||||
if (XR_FAILED(getWallsResult))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetRoomLayout] Failed to get wall count. Result: %d"), getWallsResult);
|
||||
return getWallsResult;
|
||||
}
|
||||
|
||||
TArray<XrUuidEXT> wallUuids;
|
||||
wallUuids.SetNum(roomLayout.wallUuidCountOutput);
|
||||
roomLayout.wallUuidCapacityInput = roomLayout.wallUuidCountOutput;
|
||||
roomLayout.wallUuids = wallUuids.GetData();
|
||||
|
||||
auto getDataResult = xrGetSpaceRoomLayoutFB(OpenXRHMD->GetSession(), (XrSpace)AnchorHandle, &roomLayout);
|
||||
if (XR_FAILED(getDataResult))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetRoomLayout] Failed to get room layout. Result: %d"), getDataResult);
|
||||
return getDataResult;
|
||||
}
|
||||
|
||||
OutCeilingUuid = FOculusXRUUID(roomLayout.ceilingUuid.data);
|
||||
OutFloorUuid = FOculusXRUUID(roomLayout.floorUuid.data);
|
||||
for (auto& it : wallUuids)
|
||||
{
|
||||
OutWallsUuid.Add(it.data);
|
||||
}
|
||||
|
||||
return getDataResult;
|
||||
}
|
||||
|
||||
XrResult FSceneXR::GetTriangleMesh(uint64 AnchorHandle, TArray<FVector>& Vertices, TArray<int32>& Triangles)
|
||||
{
|
||||
if (!OpenXRHMD || !OpenXRHMD->GetInstance() || !OpenXRHMD->GetSession())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetTriangleMesh] XR state is invalid."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
if (!IsSpatialEntityMeshExtensionSupported())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetTriangleMesh] Spatial entity mesh extension is unsupported."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
const XrSpaceTriangleMeshGetInfoMETA xrGetInfo{ XR_TYPE_SPACE_TRIANGLE_MESH_GET_INFO_META };
|
||||
|
||||
XrSpaceTriangleMeshMETA xrTriangleMesh{ XR_TYPE_SPACE_TRIANGLE_MESH_META, nullptr };
|
||||
xrTriangleMesh.indexCapacityInput = 0;
|
||||
xrTriangleMesh.indexCountOutput = 0;
|
||||
xrTriangleMesh.indices = nullptr;
|
||||
xrTriangleMesh.vertexCapacityInput = 0;
|
||||
xrTriangleMesh.vertexCountOutput = 0;
|
||||
xrTriangleMesh.vertices = nullptr;
|
||||
|
||||
auto getMeshCountsResult = xrGetSpaceTriangleMeshMETA((XrSpace)AnchorHandle, &xrGetInfo, &xrTriangleMesh);
|
||||
if (XR_FAILED(getMeshCountsResult))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetTriangleMesh] Failed to get vertex and index count. Result: %d"), getMeshCountsResult);
|
||||
return getMeshCountsResult;
|
||||
}
|
||||
|
||||
TArray<uint32_t> indices;
|
||||
indices.SetNum(xrTriangleMesh.indexCountOutput);
|
||||
xrTriangleMesh.indexCapacityInput = xrTriangleMesh.indexCountOutput;
|
||||
xrTriangleMesh.indices = indices.GetData();
|
||||
|
||||
TArray<XrVector3f> vertices;
|
||||
vertices.SetNum(xrTriangleMesh.vertexCountOutput);
|
||||
xrTriangleMesh.vertexCapacityInput = xrTriangleMesh.vertexCountOutput;
|
||||
xrTriangleMesh.vertices = vertices.GetData();
|
||||
|
||||
auto getMeshDataResult = xrGetSpaceTriangleMeshMETA((XrSpace)AnchorHandle, &xrGetInfo, &xrTriangleMesh);
|
||||
if (XR_FAILED(getMeshDataResult))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetTriangleMesh] Failed to get vertex and index data. Result: %d"), getMeshDataResult);
|
||||
return getMeshDataResult;
|
||||
}
|
||||
|
||||
for (auto& it : indices)
|
||||
{
|
||||
Triangles.Add(it);
|
||||
}
|
||||
|
||||
for (auto& it : vertices)
|
||||
{
|
||||
Vertices.Add(ToFVector(it));
|
||||
}
|
||||
|
||||
return getMeshDataResult;
|
||||
}
|
||||
|
||||
XrResult FSceneXR::RequestBoundaryVisibility(EOculusXRBoundaryVisibility NewVisibilityRequest)
|
||||
{
|
||||
if (!OpenXRHMD || !OpenXRHMD->GetInstance() || !OpenXRHMD->GetSession())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[RequestBoundaryVisibility] XR state is invalid."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
if (!IsBoundaryVisibilityExtensionSupported())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[RequestBoundaryVisibility] Boundary visibility extension is unsupported."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
XrSceneCaptureRequestInfoFB info{ XR_TYPE_SCENE_CAPTURE_REQUEST_INFO_FB, nullptr };
|
||||
info.request = nullptr;
|
||||
info.requestByteCount = 0;
|
||||
|
||||
XrBoundaryVisibilityMETA visibility;
|
||||
switch (NewVisibilityRequest)
|
||||
{
|
||||
case EOculusXRBoundaryVisibility::NotSuppressed:
|
||||
visibility = XR_BOUNDARY_VISIBILITY_NOT_SUPPRESSED_META;
|
||||
break;
|
||||
case EOculusXRBoundaryVisibility::Suppressed:
|
||||
visibility = XR_BOUNDARY_VISIBILITY_SUPPRESSED_META;
|
||||
break;
|
||||
default:
|
||||
visibility = XR_BOUNDARY_VISIBILITY_MAX_ENUM_META;
|
||||
}
|
||||
|
||||
auto result = xrRequestBoundaryVisibilityMETA(OpenXRHMD->GetSession(), visibility);
|
||||
if (XR_FAILED(result))
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[RequestBoundaryVisibility] Get boundary visibility failed. Result: %d"), result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
XrResult FSceneXR::GetBoundaryVisibility(EOculusXRBoundaryVisibility& OutVisibility)
|
||||
{
|
||||
if (!OpenXRHMD || !OpenXRHMD->GetInstance() || !OpenXRHMD->GetSession())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetBoundaryVisibility] XR state is invalid."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
if (!IsBoundaryVisibilityExtensionSupported())
|
||||
{
|
||||
UE_LOG(LogOculusXRScene, Warning, TEXT("[GetBoundaryVisibility] Boundary visibility extension is unsupported."));
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
OutVisibility = (LastBoundaryVisibility == XR_BOUNDARY_VISIBILITY_SUPPRESSED_META)
|
||||
? EOculusXRBoundaryVisibility::Suppressed
|
||||
: EOculusXRBoundaryVisibility::NotSuppressed;
|
||||
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
void FSceneXR::InitOpenXRFunctions(XrInstance InInstance)
|
||||
{
|
||||
// XR_FB_scene
|
||||
if (IsSceneExtensionSupported())
|
||||
{
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrGetSpaceBoundingBox2DFB", &xrGetSpaceBoundingBox2DFB);
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrGetSpaceBoundingBox3DFB", &xrGetSpaceBoundingBox3DFB);
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrGetSpaceBoundary2DFB", &xrGetSpaceBoundary2DFB);
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrGetSpaceSemanticLabelsFB", &xrGetSpaceSemanticLabelsFB);
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrGetSpaceRoomLayoutFB", &xrGetSpaceRoomLayoutFB);
|
||||
}
|
||||
|
||||
// XR_FB_scene_capture
|
||||
if (IsSceneCaptureExtensionSupported())
|
||||
{
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrRequestSceneCaptureFB", &xrRequestSceneCaptureFB);
|
||||
}
|
||||
|
||||
// XR_META_spatial_entity_mesh
|
||||
if (IsSpatialEntityMeshExtensionSupported())
|
||||
{
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrGetSpaceTriangleMeshMETA", &xrGetSpaceTriangleMeshMETA);
|
||||
}
|
||||
|
||||
// XR_META_boundary_visibility
|
||||
if (IsBoundaryVisibilityExtensionSupported())
|
||||
{
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrRequestBoundaryVisibilityMETA", &xrRequestBoundaryVisibilityMETA);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace XRScene
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "OculusXRSceneXRIncludes.h"
|
||||
#include "IOpenXRExtensionPlugin.h"
|
||||
#include "OculusXRSceneTypes.h"
|
||||
#include "OculusXRAnchorTypes.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "OculusXRScene"
|
||||
|
||||
class FOpenXRHMD;
|
||||
|
||||
namespace XRScene
|
||||
{
|
||||
extern PFN_xrGetSpaceBoundingBox2DFB xrGetSpaceBoundingBox2DFB;
|
||||
extern PFN_xrGetSpaceBoundingBox3DFB xrGetSpaceBoundingBox3DFB;
|
||||
extern PFN_xrGetSpaceBoundary2DFB xrGetSpaceBoundary2DFB;
|
||||
extern PFN_xrGetSpaceSemanticLabelsFB xrGetSpaceSemanticLabelsFB;
|
||||
extern PFN_xrRequestSceneCaptureFB xrRequestSceneCaptureFB;
|
||||
extern PFN_xrGetSpaceRoomLayoutFB xrGetSpaceRoomLayoutFB;
|
||||
extern PFN_xrGetSpaceTriangleMeshMETA xrGetSpaceTriangleMeshMETA;
|
||||
extern PFN_xrRequestBoundaryVisibilityMETA xrRequestBoundaryVisibilityMETA;
|
||||
|
||||
class FSceneXR : public IOpenXRExtensionPlugin
|
||||
{
|
||||
public:
|
||||
// IOculusXROpenXRHMDPlugin
|
||||
virtual bool GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
|
||||
virtual bool GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
|
||||
virtual const void* OnCreateInstance(class IOpenXRHMDModule* InModule, const void* InNext) override;
|
||||
virtual const void* OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext) override;
|
||||
virtual void OnDestroySession(XrSession InSession) override;
|
||||
virtual void OnEvent(XrSession InSession, const XrEventDataBaseHeader* InHeader) override;
|
||||
|
||||
public:
|
||||
FSceneXR();
|
||||
virtual ~FSceneXR();
|
||||
void RegisterAsOpenXRExtension();
|
||||
|
||||
bool IsSceneExtensionSupported() const { return bExtSceneEnabled; }
|
||||
bool IsSceneCaptureExtensionSupported() const { return bExtSceneCaptureEnabled; }
|
||||
bool IsBoundaryVisibilityExtensionSupported() const { return bExtBoundaryVisibilityEnabled; }
|
||||
bool IsSpatialEntityMeshExtensionSupported() const { return bExtSpatialEntityMeshEnabled; }
|
||||
|
||||
XrResult GetScenePlane(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize);
|
||||
XrResult GetSceneVolume(uint64 AnchorHandle, FVector& OutPos, FVector& OutSize);
|
||||
XrResult GetBoundary2D(uint64 AnchorHandle, TArray<FVector2f>& OutVertices);
|
||||
XrResult GetSemanticClassification(uint64 AnchorHandle, TArray<FString>& OutSemanticClassifications);
|
||||
|
||||
XrResult RequestSceneCapture(uint64& OutRequestID);
|
||||
XrResult GetRoomLayout(uint64 AnchorHandle, const uint32 MaxWallsCapacity, FOculusXRUUID& OutCeilingUuid, FOculusXRUUID& OutFloorUuid, TArray<FOculusXRUUID>& OutWallsUuid);
|
||||
XrResult GetTriangleMesh(uint64 AnchorHandle, TArray<FVector>& Vertices, TArray<int32>& Triangles);
|
||||
|
||||
XrResult RequestBoundaryVisibility(EOculusXRBoundaryVisibility NewVisibilityRequest);
|
||||
XrResult GetBoundaryVisibility(EOculusXRBoundaryVisibility& OutVisibility);
|
||||
|
||||
private:
|
||||
void InitOpenXRFunctions(XrInstance InInstance);
|
||||
|
||||
bool bExtSceneEnabled;
|
||||
bool bExtSceneCaptureEnabled;
|
||||
bool bExtBoundaryVisibilityEnabled;
|
||||
bool bExtSpatialEntityMeshEnabled;
|
||||
|
||||
XrBoundaryVisibilityMETA LastBoundaryVisibility;
|
||||
FOpenXRHMD* OpenXRHMD;
|
||||
};
|
||||
|
||||
} // namespace XRScene
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,7 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <khronos/openxr/openxr.h>
|
||||
#include <khronos/openxr/meta_openxr_preview/meta_boundary_visibility.h>
|
||||
#include "openxr/OculusXRAnchorsXRIncludes.h"
|
||||
Reference in New Issue
Block a user