331 lines
9.3 KiB
C++
331 lines
9.3 KiB
C++
// Copyright® 2015-2023 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.
|
||
// Unreal® Engine, Copyright 1998 – 2023, Epic Games, Inc. All rights reserved.
|
||
|
||
#include "PICO_SpatialMeshActor.h"
|
||
|
||
#include "MRMeshComponent.h"
|
||
#include "PICOOpenXRRuntimeSettings.h"
|
||
#include "PICO_MRAsyncActions.h"
|
||
#include "PICO_MRFunctionLibrary.h"
|
||
#include "PICO_SpatialMesh.h"
|
||
#include "ProceduralMeshComponent.h"
|
||
#include "Algo/Transform.h"
|
||
#include "UObject/ConstructorHelpers.h"
|
||
|
||
#define UPDATE_FRAME_NUM_MAX 10
|
||
|
||
|
||
ASpatialMeshActorPICO::ASpatialMeshActorPICO(const FObjectInitializer& ObjectInitializer)
|
||
{
|
||
PrimaryActorTick.bCanEverTick = true;
|
||
PrimaryActorTick.bStartWithTickEnabled = false;
|
||
|
||
SpatialMeshMaterial=nullptr;
|
||
|
||
for (ESemanticLabelPICO Val : TEnumRange<ESemanticLabelPICO>())
|
||
{
|
||
SemanticToColors.Emplace(Val, FColor::MakeRandomSeededColor(static_cast<int32>(Val)));
|
||
}
|
||
}
|
||
|
||
void ASpatialMeshActorPICO::BeginPlay()
|
||
{
|
||
Super::BeginPlay();
|
||
|
||
USceneComponent* RootSceneComponent = NewObject<USceneComponent>(this, USceneComponent::StaticClass());
|
||
RootSceneComponent->SetMobility(EComponentMobility::Static);
|
||
RootSceneComponent->RegisterComponent();
|
||
SetRootComponent(RootSceneComponent);
|
||
|
||
if (bDrawOnBeginPlay)
|
||
{
|
||
StartDraw();
|
||
}
|
||
}
|
||
|
||
void ASpatialMeshActorPICO::HandleMeshDataUpdatedEvent()
|
||
{
|
||
URequestSpatialMeshPICO_AsyncAction* RequestSpatialMeshAction = URequestSpatialMeshPICO_AsyncAction::RequestSpatialMeshInfosPICO_Async();
|
||
RequestSpatialMeshAction->OnSuccess.AddDynamic(this, &ASpatialMeshActorPICO::HandleRequestSpatialMeshContentsEvent);
|
||
RequestSpatialMeshAction->Activate();
|
||
}
|
||
|
||
void ASpatialMeshActorPICO::Tick(float DeltaTime)
|
||
{
|
||
if (bEnableDebugFunction)
|
||
{
|
||
NumDrawCalls = GNumDrawCallsRHI[0];
|
||
DrawnPrimitives = GNumPrimitivesDrawnRHI[0];
|
||
}
|
||
|
||
TArray<FSpatialMeshInfoPICO> MRMeshInfos;
|
||
MeshInfoQueue.Dequeue(MRMeshInfos);
|
||
|
||
for (auto MeshInfo : MRMeshInfos)
|
||
{
|
||
|
||
switch (MeshInfo.State)
|
||
{
|
||
case ESpatialMeshStatePICO::Added:
|
||
{
|
||
USpatialMeshComponentPICO* SpatialMesh = NewObject<USpatialMeshComponentPICO>(this);
|
||
SpatialMesh->RegisterComponent();
|
||
SpatialMesh->SetMaterial(0,SpatialMeshMaterial);
|
||
SpatialMesh->SetUseWireframe(false);
|
||
SpatialMesh->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepWorldTransform);
|
||
SpatialMesh->SetVisibility(bSpatialMeshVisible);
|
||
SpatialMesh->SetCollisionEnabled(CollisionType);
|
||
SpatialMesh->SetEnableMeshOcclusion(true);
|
||
AddOwnedComponent(SpatialMesh);
|
||
|
||
if (EntityToMeshMap.Contains(MeshInfo.UUID))
|
||
{
|
||
if (EntityToMeshMap[MeshInfo.UUID]!=nullptr)
|
||
{
|
||
EntityToMeshMap[MeshInfo.UUID]->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||
EntityToMeshMap[MeshInfo.UUID]->DestroyComponent();
|
||
}
|
||
EntityToMeshMap.Remove(MeshInfo.UUID);
|
||
}
|
||
|
||
EntityToMeshMap.Emplace(MeshInfo.UUID, SpatialMesh);
|
||
|
||
UpdateMeshByMeshInfo(SpatialMesh, MeshInfo);
|
||
}
|
||
break;
|
||
case ESpatialMeshStatePICO::Stable:
|
||
break;
|
||
case ESpatialMeshStatePICO::Updated:
|
||
{
|
||
if (EntityToMeshMap.Contains(MeshInfo.UUID))
|
||
{
|
||
if (EntityToMeshMap[MeshInfo.UUID] == nullptr)
|
||
{
|
||
continue;
|
||
}
|
||
UpdateMeshByMeshInfo(EntityToMeshMap[MeshInfo.UUID], MeshInfo);
|
||
}
|
||
}
|
||
break;
|
||
case ESpatialMeshStatePICO::Removed:
|
||
{
|
||
if (EntityToMeshMap.Contains(MeshInfo.UUID)
|
||
&&EntityToMeshMap[MeshInfo.UUID]!=nullptr)
|
||
{
|
||
|
||
EntityToMeshMap[MeshInfo.UUID]->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||
EntityToMeshMap[MeshInfo.UUID]->DestroyComponent();
|
||
EntityToMeshMap.Remove(MeshInfo.UUID);
|
||
}
|
||
else
|
||
{
|
||
}
|
||
}
|
||
break;
|
||
default: ;
|
||
}
|
||
}
|
||
}
|
||
|
||
void ASpatialMeshActorPICO::HandleRequestSpatialMeshContentsEvent(EResultPICO Result, const TArray<FSpatialMeshInfoPICO>& MeshInfos)
|
||
{
|
||
TArray<FSpatialMeshInfoPICO> MRMeshInfos = {};
|
||
int32 Counter = 0;
|
||
bool bIsDone = false;
|
||
const int32 MeshCountPerFrame= FMath::CeilToInt((static_cast<float>(MeshInfos.Num())) / UPDATE_FRAME_NUM_MAX);
|
||
|
||
for (auto MeshInfo : MeshInfos)
|
||
{
|
||
Counter++;
|
||
if (Counter < MeshCountPerFrame)
|
||
{
|
||
bIsDone = false;
|
||
MRMeshInfos.Add(MeshInfo);
|
||
}
|
||
else
|
||
{
|
||
bIsDone = true;
|
||
MRMeshInfos.Add(MeshInfo);
|
||
MeshInfoQueue.Enqueue(MRMeshInfos);
|
||
Counter = 0;
|
||
MRMeshInfos.Empty();
|
||
}
|
||
}
|
||
|
||
if (!bIsDone)
|
||
{
|
||
MeshInfoQueue.Enqueue(MRMeshInfos);
|
||
MRMeshInfos.Empty();
|
||
}
|
||
}
|
||
|
||
void ASpatialMeshActorPICO::EndPlay(EEndPlayReason::Type Reason)
|
||
{
|
||
ClearMesh();
|
||
}
|
||
|
||
bool ASpatialMeshActorPICO::StartDraw()
|
||
{
|
||
SetActorTickEnabled(true);
|
||
if (!UMRFunctionLibraryPICO::GetMRDelegateManagerPICO()->MeshDataUpdatedDelegate.Contains(this, GET_FUNCTION_NAME_CHECKED(ASpatialMeshActorPICO, HandleMeshDataUpdatedEvent)))
|
||
{
|
||
UMRFunctionLibraryPICO::GetMRDelegateManagerPICO()->MeshDataUpdatedDelegate.AddDynamic(this, &ASpatialMeshActorPICO::HandleMeshDataUpdatedEvent);
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
bool ASpatialMeshActorPICO::PauseDraw()
|
||
{
|
||
SetActorTickEnabled(false);
|
||
if (UMRFunctionLibraryPICO::GetMRDelegateManagerPICO()->MeshDataUpdatedDelegate.Contains(this, GET_FUNCTION_NAME_CHECKED(ASpatialMeshActorPICO, HandleMeshDataUpdatedEvent)))
|
||
{
|
||
UMRFunctionLibraryPICO::GetMRDelegateManagerPICO()->MeshDataUpdatedDelegate.RemoveDynamic(this, &ASpatialMeshActorPICO::HandleMeshDataUpdatedEvent);
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
void ASpatialMeshActorPICO::SetMeshVisibility(bool visibility)
|
||
{
|
||
bSpatialMeshVisible = visibility;
|
||
for (const auto Pair : EntityToMeshMap)
|
||
{
|
||
if (Pair.Value)
|
||
{
|
||
Pair.Value->SetVisibility(visibility);
|
||
}
|
||
}
|
||
}
|
||
|
||
void ASpatialMeshActorPICO::EnableDebugFunction(bool bEnable)
|
||
{
|
||
bEnableDebugFunction = bEnable;
|
||
}
|
||
|
||
bool ASpatialMeshActorPICO::ClearMesh()
|
||
{
|
||
for (const auto Pair : EntityToMeshMap)
|
||
{
|
||
if (Pair.Value)
|
||
{
|
||
Pair.Value->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||
Pair.Value->Clear();
|
||
Pair.Value->DestroyComponent();
|
||
}
|
||
}
|
||
EntityToMeshMap.Empty();
|
||
MeshInfoQueue.Empty();
|
||
FSpatialMeshExtensionPICO::GetInstance()->ClearMeshProviderBuffer();
|
||
|
||
return true;
|
||
}
|
||
|
||
int32 ASpatialMeshActorPICO::GetMeshNum()
|
||
{
|
||
return EntityToMeshMap.Num();
|
||
}
|
||
|
||
int32 ASpatialMeshActorPICO::GetDrawsNum()
|
||
{
|
||
return NumDrawCalls;
|
||
}
|
||
|
||
int32 ASpatialMeshActorPICO::GetDrawnPrimitives()
|
||
{
|
||
return DrawnPrimitives;
|
||
}
|
||
|
||
FColor ASpatialMeshActorPICO::GetColorBySceneLabel(ESemanticLabelPICO SceneLabel)
|
||
{
|
||
return SemanticToColors.Contains(SceneLabel)?SemanticToColors[SceneLabel]:FColor::MakeRandomSeededColor(static_cast<int32>(SceneLabel));
|
||
}
|
||
|
||
bool ASpatialMeshActorPICO::UpdateMeshByMeshInfo(USpatialMeshComponentPICO* SpatialMesh, const FSpatialMeshInfoPICO& MeshInfo)
|
||
{
|
||
if (SpatialMesh)
|
||
{
|
||
TArray<MRMESH_INDEX_TYPE> TempIndices;
|
||
TArray<FVector> TempVertices;
|
||
TArray<FColor> VertexColors;
|
||
const UPICOOpenXRRuntimeSettings* Settings = GetDefault<UPICOOpenXRRuntimeSettings>();
|
||
TArray<FVector> EmptyNormals;
|
||
TArray<FVector2D> EmptyUV;
|
||
|
||
if (Settings->bSemanticsAlignWithTriangle)
|
||
{
|
||
for (int32 Index = 0; Index < MeshInfo.Semantics.Num(); ++Index)
|
||
{
|
||
ESemanticLabelPICO Semantic = MeshInfo.Semantics[Index];
|
||
int32 IndicesIndex = Index * 3;
|
||
|
||
if (MeshInfo.Indices.IsValidIndex(IndicesIndex + 0)
|
||
&& MeshInfo.Indices.IsValidIndex(IndicesIndex + 1)
|
||
&& MeshInfo.Indices.IsValidIndex(IndicesIndex + 2))
|
||
{
|
||
int32 VerticesIndex0 = MeshInfo.Indices[IndicesIndex + 0];
|
||
int32 VerticesIndex1 = MeshInfo.Indices[IndicesIndex + 1];
|
||
int32 VerticesIndex2 = MeshInfo.Indices[IndicesIndex + 2];
|
||
|
||
int32 IndicesStart = TempVertices.Num();
|
||
|
||
if (MeshInfo.Vertices.IsValidIndex(VerticesIndex0)
|
||
&& MeshInfo.Vertices.IsValidIndex(VerticesIndex1)
|
||
&& MeshInfo.Vertices.IsValidIndex(VerticesIndex2))
|
||
{
|
||
TempVertices.Add(MeshInfo.Vertices[VerticesIndex0]);
|
||
TempVertices.Add(MeshInfo.Vertices[VerticesIndex1]);
|
||
TempVertices.Add(MeshInfo.Vertices[VerticesIndex2]);
|
||
|
||
TempIndices.Add(IndicesStart + 0);
|
||
TempIndices.Add(IndicesStart + 1);
|
||
TempIndices.Add(IndicesStart + 2);
|
||
|
||
VertexColors.Add(GetColorBySceneLabel(Semantic));
|
||
VertexColors.Add(GetColorBySceneLabel(Semantic));
|
||
VertexColors.Add(GetColorBySceneLabel(Semantic));
|
||
|
||
SpatialMesh->AddAnchorToSceneLabel(Index, Semantic);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
TempVertices = MeshInfo.Vertices;
|
||
if (Settings->bSemanticsAlignWithVertex)
|
||
{
|
||
for (int32 Index = 0; Index < MeshInfo.Semantics.Num(); ++Index)
|
||
{
|
||
ESemanticLabelPICO Semantic = MeshInfo.Semantics[Index];
|
||
VertexColors.Add(GetColorBySceneLabel(Semantic));
|
||
}
|
||
|
||
for (int32 Index = 0; Index < MeshInfo.Indices.Num() / 3; ++Index)
|
||
{
|
||
ESemanticLabelPICO SemanticLabel = MeshInfo.Semantics[MeshInfo.Indices[Index * 3]];
|
||
SpatialMesh->AddAnchorToSceneLabel(Index, SemanticLabel);
|
||
}
|
||
}
|
||
|
||
if (MeshInfo.Vertices.Num() && MeshInfo.Indices.Num())
|
||
{
|
||
TempIndices.Empty(MeshInfo.Indices.Num());
|
||
Algo::Transform(MeshInfo.Indices, TempIndices, [](const auto& Indice) { return static_cast<MRMESH_INDEX_TYPE>(Indice); });
|
||
}
|
||
}
|
||
|
||
if (TempVertices.Num() && TempIndices.Num())
|
||
{
|
||
SpatialMesh->UpdateMesh(MeshInfo.MeshPose.GetLocation(), MeshInfo.MeshPose.GetRotation(),
|
||
FVector(1, 1, 1), TempVertices, TempIndices, TArray<FVector2D>(), TArray<FPackedNormal>(), VertexColors);
|
||
}
|
||
}
|
||
|
||
|
||
return false;
|
||
}
|