October3d55/M/PICOXRPlugin/Source/PICOXRMR/Private/PXR_MRFunctionLibrary.cpp

447 lines
15 KiB
C++
Raw Normal View History

2025-07-29 14:53:32 +08:00
// Copyright PICO Technology Co., Ltd. All rights reserved.
// This plugin incorporates portions of the Unreal® Engine. Unreal® is a trademark or registered trademark of Epic Games, Inc. in the United States of America and elsewhere.
// Copyright Epic Games, Inc. All Rights Reserved.
#include "PXR_MRFunctionLibrary.h"
#include "PXR_ProviderManager.h"
#include "MRMeshComponent.h"
bool UPICOXRMRFunctionLibrary::PXR_GetAnchorEntityUuid(AActor* BoundActor, FPICOSpatialUUID& OutAnchorUUID,EPICOResult& OutResult)
{
if (FPICOProviderManager::ShouldUseLegacyMR())
{
return PXR_AnchorProvider::GetInstance()->GetAnchorEntityUUIDLegacy(BoundActor, OutAnchorUUID);
}
return PXR_AnchorProvider::GetInstance()->GetAnchorEntityUUID(BoundActor, OutAnchorUUID,OutResult);
}
bool UPICOXRMRFunctionLibrary::PXR_GetAnchorEntityUuidByComponent(const UPICOAnchorComponent* AnchorComponent, FPICOSpatialUUID& OutAnchorUUID, EPICOResult& OutResult)
{
if (FPICOProviderManager::ShouldUseLegacyMR())
{
return PXR_AnchorProvider::GetInstance()->GetAnchorEntityUUIDLegacyByComponent(AnchorComponent, OutAnchorUUID);
}
return PXR_AnchorProvider::GetInstance()->GetAnchorEntityUUIDByComponent(AnchorComponent, OutAnchorUUID,OutResult);
}
bool UPICOXRMRFunctionLibrary::PXR_GetSceneBoundingBox2D(const FPICOSpatialUUID& UUID, FPICOBoundingBox2D& Box2D)
{
if (FPICOProviderManager::ShouldUseLegacyMR())
{
return PXR_AnchorProvider::GetInstance()->GetSpatialSceneBoundingBox2DLegacy(UUID,Box2D);
}
return PXR_SceneProvider::GetInstance()->GetSpatialSceneBoundingBox2D(UUID, Box2D);
}
bool UPICOXRMRFunctionLibrary::PXR_GetSceneBoundingPolygon(const FPICOSpatialUUID& UUID, TArray<FVector>& OutPolygonVertices)
{
if (FPICOProviderManager::ShouldUseLegacyMR())
{
return PXR_AnchorProvider::GetInstance()->GetSpatialSceneBoundingPolygonLegacy(UUID,OutPolygonVertices);
}
return PXR_SceneProvider::GetInstance()->GetSpatialSceneBoundingPolygon(UUID, OutPolygonVertices);
}
bool UPICOXRMRFunctionLibrary::PXR_GetSceneBoundingBox3D(const FPICOSpatialUUID& UUID, FPICOBoundingBox3D& Box3D)
{
if (FPICOProviderManager::ShouldUseLegacyMR())
{
return PXR_AnchorProvider::GetInstance()->GetSpatialSceneBoundingBox3DLegacy(UUID,Box3D);
}
return PXR_SceneProvider::GetInstance()->GetSpatialSceneBoundingBox3D(UUID, Box3D);
}
bool UPICOXRMRFunctionLibrary::PXR_GetAnchorPoseByActor(AActor* BoundActor, FTransform& OutTransform,EPICOResult& OutResult)
{
if (!IsValid(BoundActor) || !IsValid(BoundActor->GetWorld()))
{
return false;
}
UPICOAnchorComponent* AnchorComponent = Cast<UPICOAnchorComponent>(BoundActor->GetComponentByClass(UPICOAnchorComponent::StaticClass()));
if (IsValid(AnchorComponent) && AnchorComponent->IsAnchorValid())
{
if (FPICOProviderManager::ShouldUseLegacyMR())
{
return PXR_AnchorProvider::GetInstance()->GetAnchorPoseLegacy(AnchorComponent, OutTransform);
}
return PXR_AnchorProvider::GetInstance()->GetAnchorPose(AnchorComponent, OutTransform,OutResult);
}
return false;
}
bool UPICOXRMRFunctionLibrary::PXR_GetAnchorPoseByComponent(UPICOAnchorComponent* AnchorComponent, FTransform& OutTransform,EPICOResult& OutResult)
{
if (IsValid(AnchorComponent) && AnchorComponent->IsAnchorValid())
{
if (FPICOProviderManager::ShouldUseLegacyMR())
{
return PXR_AnchorProvider::GetInstance()->GetAnchorPoseLegacy(AnchorComponent, OutTransform);
}
return PXR_AnchorProvider::GetInstance()->GetAnchorPose(AnchorComponent, OutTransform,OutResult);
}
return false;
}
AActor* UPICOXRMRFunctionLibrary::PXR_SpawnActorFromLoadResult(UObject* WorldContext, const FAnchorLoadResult& LoadResult, UClass* ActorClass)
{
UWorld* World = GEngine->GetWorldFromContextObject(WorldContext, EGetWorldErrorMode::ReturnNull);
if (!IsValid(World))
{
PXR_LOGV(PxrMR, "UPICOXRMRFunctionLibrary::PXR_SpawnActorFromLoadResult is Invalid");
return nullptr;
}
FActorSpawnParameters SpawnInfo;
SpawnInfo.ObjectFlags |= RF_Transient;
AActor* AnchorActor = World->SpawnActor(ActorClass, nullptr, nullptr, SpawnInfo);
if (!IsValid(AnchorActor))
{
PXR_LOGV(PxrMR, "UPICOXRMRFunctionLibrary::PXR_SpawnActorFromLoadResult Spawn Actor Failed");
return nullptr;
}
UPICOAnchorComponent* AnchorComponent = Cast<UPICOAnchorComponent>(AnchorActor->GetComponentByClass(UPICOAnchorComponent::StaticClass()));
if (IsValid(AnchorComponent) && AnchorComponent->IsAnchorValid())
{
PXR_LOGV(PxrMR, "UPICOXRMRFunctionLibrary::PXR_SpawnActorFromLoadResult Anchor is Already Valid, Return Old Anchor Actor");
return AnchorActor;
}
if (AnchorComponent == nullptr)
{
AnchorComponent = Cast<UPICOAnchorComponent>(AnchorActor->AddComponentByClass(UPICOAnchorComponent::StaticClass(), false, FTransform::Identity, false));
}
AnchorComponent->SetAnchorHandle(LoadResult.AnchorHandle);
return AnchorActor;
}
bool UPICOXRMRFunctionLibrary::PXR_IsAnchorValidForActor(AActor* BoundActor)
{
if (!IsValid(BoundActor))
{
return false;
}
UPICOAnchorComponent* AnchorComponent = Cast<UPICOAnchorComponent>(BoundActor->GetComponentByClass(UPICOAnchorComponent::StaticClass()));
if (IsValid(AnchorComponent) && AnchorComponent->IsAnchorValid())
{
return true;
}
return false;
}
bool UPICOXRMRFunctionLibrary::PXR_IsAnchorValidForComponent(UPICOAnchorComponent* AnchorComponent)
{
if (IsValid(AnchorComponent) && AnchorComponent->IsAnchorValid())
{
return true;
}
return false;
}
FString UPICOXRMRFunctionLibrary::PXR_FromAnchorToString(const FPICOSpatialHandle& Anchor)
{
return Anchor.ToString();
}
FString UPICOXRMRFunctionLibrary::PXR_FromUUIDToString(const FPICOSpatialUUID& AnchorUUID)
{
return AnchorUUID.ToString();
}
FPICOSpatialUUID UPICOXRMRFunctionLibrary::PXR_FromStringToUUID(const FString& AnchorUUIDString)
{
FPICOSpatialUUID OutAnchorUUID;
TArray<FString> UUIDArray;
AnchorUUIDString.ParseIntoArray(UUIDArray, TEXT("-"));
if (UUIDArray.Num() == PXR_UUID_SIZE)
{
for (int32 Index = 0; Index < PXR_UUID_SIZE; ++Index)
{
OutAnchorUUID.UUIDArray[Index] = (uint64_t)FCString::Strtoui64(*UUIDArray[Index], nullptr, 16);
}
}
return OutAnchorUUID;
}
bool UPICOXRMRFunctionLibrary::PXR_CloseSpatialMeshScanning()
{
return FPICOProviderManager::PXR_StopSenseDataProvider(EPICOProviderType::Pico_Provider_Mesh);
}
bool UPICOXRMRFunctionLibrary::PXR_ChangeSpatialMeshLodSetting(EPICOSpatialMeshLod SpatialMeshLod)
{
bool bResult=false;
if (PXR_MeshProvider::GetInstance()->GetCurrentSpatialMeshLod()!=SpatialMeshLod)
{
bResult=FPICOProviderManager::PXR_StopSenseDataProvider(EPICOProviderType::Pico_Provider_Mesh);
if (bResult)
{
bResult=FPICOProviderManager::PXR_DestroySenseDataProvider(EPICOProviderType::Pico_Provider_Mesh);
if (bResult)
{
FPICOSenseDataProviderCreateInfoMesh cFPICOSenseDataProviderCreateInfoMesh = {};
cFPICOSenseDataProviderCreateInfoMesh.Lod = SpatialMeshLod;
const UPICOXRSettings* Settings = GetDefault<UPICOXRSettings>();
if(Settings)
{
if (Settings->bSemanticsAlignWithTriangle)
{
cFPICOSenseDataProviderCreateInfoMesh.ConfigArray.Add(EPICOSpatialMeshConfig::Spatial_Mesh_Config_Semantic);
}
else if (Settings->bSemanticsAlignWithVertex)
{
cFPICOSenseDataProviderCreateInfoMesh.ConfigArray.Add(EPICOSpatialMeshConfig::Spatial_Mesh_Config_Semantic);
cFPICOSenseDataProviderCreateInfoMesh.ConfigArray.Add(EPICOSpatialMeshConfig::Spatial_Mesh_Config_Semantic_Align_With_Vertex);
}
}
bResult=FPICOProviderManager::PXR_CreateSenseDataProvider(cFPICOSenseDataProviderCreateInfoMesh);
}
}
}
return bResult;
}
EPICOSpatialMeshLod UPICOXRMRFunctionLibrary::PXR_GetSpatialMeshLodSetting()
{
return PXR_MeshProvider::GetInstance()->GetCurrentSpatialMeshLod();
}
EPICOMRState UPICOXRMRFunctionLibrary::PXR_GetSpatialMeshScanningState()
{
return PXR_MeshProvider::GetInstance()->GetSenseDataProviderState();
}
EPICOMRState UPICOXRMRFunctionLibrary::PXR_GetSpatialAnchorServiceState()
{
return PXR_AnchorProvider::GetInstance()->GetSenseDataProviderState();
}
EPICOMRState UPICOXRMRFunctionLibrary::PXR_GetSceneCaptureServiceState()
{
return PXR_SceneProvider::GetInstance()->GetSenseDataProviderState();
}
void UPICOXRMRFunctionLibrary::PXR_ResetSpatialMeshInfosState()
{
PXR_MeshProvider::GetInstance()->ClearMeshProviderBuffer();
}
bool UPICOXRMRFunctionLibrary::PXR_CloseSpatialAnchorService()
{
return FPICOProviderManager::PXR_StopSenseDataProvider(EPICOProviderType::Pico_Provider_Anchor);
}
bool UPICOXRMRFunctionLibrary::PXR_CloseSceneCaptureService()
{
return FPICOProviderManager::PXR_StopSenseDataProvider(EPICOProviderType::Pico_Provider_Scene_Capture);
}
bool UPICOXRMRFunctionLibrary::PXR_DestroyAnchorByComponent(UPICOAnchorComponent* AnchorComponent,EPICOResult& OutResult)
{
bool bResult=false;
if (IsValid(AnchorComponent) && AnchorComponent->IsAnchorValid())
{
if (FPICOProviderManager::ShouldUseLegacyMR())
{
bResult=PXR_AnchorProvider::GetInstance()->DestroyAnchorByHandleLegacy(AnchorComponent->GetAnchorHandle());
}
else
{
bResult=PXR_AnchorProvider::GetInstance()->DestroyAnchorByHandle(AnchorComponent->GetAnchorHandle(),OutResult);
}
AnchorComponent->ResetAnchorHandle();
}
return bResult;
}
bool UPICOXRMRFunctionLibrary::PXR_DestroyAnchorByActor(AActor* BoundActor,EPICOResult& OutResult)
{
bool bResult=false;
if (!IsValid(BoundActor) || !IsValid(BoundActor->GetWorld()))
{
return bResult;
}
UPICOAnchorComponent* AnchorComponent = Cast<UPICOAnchorComponent>(BoundActor->GetComponentByClass(UPICOAnchorComponent::StaticClass()));
if (IsValid(AnchorComponent) && AnchorComponent->IsAnchorValid())
{
if (FPICOProviderManager::ShouldUseLegacyMR())
{
bResult=PXR_AnchorProvider::GetInstance()->DestroyAnchorByHandleLegacy(AnchorComponent->GetAnchorHandle());
}
else
{
bResult=PXR_AnchorProvider::GetInstance()->DestroyAnchorByHandle(AnchorComponent->GetAnchorHandle(),OutResult);
}
AnchorComponent->ResetAnchorHandle();
}
return bResult;
}
bool UPICOXRMRFunctionLibrary::PXR_CreateSceneBoundingPolygon(AActor* BoundActor,bool bNeverCreateCollision,bool bFlipPolygon,bool UseWireframe, const FTransform& Transform, const TArray<FVector>& BoundaryVertices,UMaterialInterface* DefaultMeshMaterial)
{
auto MRMeshComponent = NewObject<UProceduralMeshComponent>(BoundActor);
TArray<int32> Indices;
TArray<FVector> Normals;
TArray<FLinearColor> VertexColors;
TArray<FProcMeshTangent> Tangents;
TArray<FVector2D> UV0;
if (!IsValid(BoundActor)||!BoundaryVertices.Num()||!DefaultMeshMaterial)
{
return false;
}
MRMeshComponent->SetUsingAbsoluteLocation(true);
MRMeshComponent->SetUsingAbsoluteRotation(true);
MRMeshComponent->SetUsingAbsoluteScale(true);
MRMeshComponent->SetMaterial(0, DefaultMeshMaterial);
MRMeshComponent->SetupAttachment(BoundActor->GetRootComponent());
MRMeshComponent->RegisterComponent();
auto Vertices = BoundaryVertices;
const auto NumPolygons = Vertices.Num();
Indices.Reset(3 * NumPolygons);
if (bFlipPolygon)
{
for (auto Index = 0; Index < NumPolygons; ++Index)
{
Indices.Add(0);
Indices.Add((Index + 2) % NumPolygons);
Indices.Add((Index + 1) % NumPolygons);
}
}
else
{
for (auto Index = 0; Index < NumPolygons; ++Index)
{
Indices.Add(0);
Indices.Add((Index + 1) % NumPolygons);
Indices.Add((Index + 2) % NumPolygons);
}
}
MRMeshComponent->CreateMeshSection_LinearColor(0, Vertices, Indices, Normals, UV0, VertexColors, Tangents, !bNeverCreateCollision);
MRMeshComponent->SetWorldLocation(Transform.GetLocation());
MRMeshComponent->SetWorldRotation(Transform.GetRotation());
return true;
}
bool UPICOXRMRFunctionLibrary::PXR_CreateSceneBoundingPolygonWithUVAdjustment(AActor* BoundActor, bool bNeverCreateCollision, bool bFlipPolygon, const FPICOUVAdjustment& UVAdjustment, const FTransform& Transform, const TArray<FVector>& BoundaryVertices, UMaterialInterface* DefaultMeshMaterial)
{
auto MRMeshComponent = NewObject<UProceduralMeshComponent>(BoundActor);
if (!IsValid(BoundActor) || !BoundaryVertices.Num() || !DefaultMeshMaterial)
{
return false;
}
MRMeshComponent->SetUsingAbsoluteLocation(true);
MRMeshComponent->SetUsingAbsoluteRotation(true);
MRMeshComponent->SetUsingAbsoluteScale(true);
MRMeshComponent->SetMaterial(0, DefaultMeshMaterial);
MRMeshComponent->SetupAttachment(BoundActor->GetRootComponent());
MRMeshComponent->RegisterComponent();
auto Vertices = BoundaryVertices;
const auto NumPolygons = Vertices.Num();
TArray<int32> Indices;
TArray<FVector> Normals;
TArray<FLinearColor> VertexColors;
TArray<FProcMeshTangent> Tangents;
TArray<FVector2D> UV0;
Normals.Reserve(NumPolygons);
UV0.Reserve(NumPolygons);
Indices.Reserve(3 * NumPolygons);
const int Index1 = bFlipPolygon ? 2 : 1;
const int Index2 = bFlipPolygon ? 1 : 2;
const FVector Normal = -FVector::XAxisVector;
for (auto Index = 0; Index < NumPolygons; ++Index)
{
Indices.Add(0);
Indices.Add((Index + Index1) % NumPolygons);
Indices.Add((Index + Index2) % NumPolygons);
Normals.Push(Normal);
}
// Calculate UV coordinates
// First, find the bounding box of the vertices
FVector MinBounds(FLT_MAX, FLT_MAX, FLT_MAX);
FVector MaxBounds(-FLT_MAX, -FLT_MAX, -FLT_MAX);
for (const auto& Vertex : Vertices)
{
// Manually update the minimum bounds
if (Vertex.X < MinBounds.X) MinBounds.X = Vertex.X;
if (Vertex.Y < MinBounds.Y) MinBounds.Y = Vertex.Y;
if (Vertex.Z < MinBounds.Z) MinBounds.Z = Vertex.Z;
// Manually update the maximum bounds
if (Vertex.X > MaxBounds.X) MaxBounds.X = Vertex.X;
if (Vertex.Y > MaxBounds.Y) MaxBounds.Y = Vertex.Y;
if (Vertex.Z > MaxBounds.Z) MaxBounds.Z = Vertex.Z;
}
// Calculate the size of the bounding box
FVector BoundsSize = MaxBounds - MinBounds;
// Calculate UV coordinates for each vertex
for (const auto& Vertex : Vertices)
{
// Map the vertex position to the [0, 1] range
FVector2D UV;
#if WITH_EDITOR
UV.X = (Vertex.X - MinBounds.X) / BoundsSize.X;
UV.Y = bFlipPolygon? 1 - (Vertex.Y - MinBounds.Y) / BoundsSize.Y : (Vertex.Y - MinBounds.Y) / BoundsSize.Y;
#else
UV.X = (Vertex.Y - MinBounds.Y) / BoundsSize.Y;
UV.Y = bFlipPolygon? 1 - (Vertex.Z - MinBounds.Z) / BoundsSize.Z : (Vertex.Z - MinBounds.Z) / BoundsSize.Z;
#endif
float rotationInRadians = FMath::DegreesToRadians(UVAdjustment.Rotation);
float cosAngle = FMath::Cos(rotationInRadians);
float sinAngle = FMath::Sin(rotationInRadians);
FVector2D rotatedUV;
rotatedUV.X = UV.X * cosAngle - UV.Y * sinAngle;
rotatedUV.Y = UV.X * sinAngle + UV.Y * cosAngle;
UV = rotatedUV * UVAdjustment.Scale + UVAdjustment.Offset;
UV0.Add(UV);
}
MRMeshComponent->CreateMeshSection_LinearColor(0, Vertices, Indices, Normals, UV0, VertexColors, Tangents, !bNeverCreateCollision);
MRMeshComponent->SetWorldLocation(Transform.GetLocation());
MRMeshComponent->SetWorldRotation(Transform.GetRotation());
return true;
}