2025-03-10 09:43:27 +08:00
// 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"
2025-07-21 10:22:56 +08:00
# include "Materials/Material.h"
# include "Materials/MaterialInterface.h"
2025-03-10 09:43:27 +08:00
2025-07-21 10:22:56 +08:00
# define UPDATE_FRAME_NUM_MAX 20
2025-03-10 09:43:27 +08:00
ASpatialMeshActorPICO : : ASpatialMeshActorPICO ( const FObjectInitializer & ObjectInitializer )
{
PrimaryActorTick . bCanEverTick = true ;
PrimaryActorTick . bStartWithTickEnabled = false ;
2025-07-21 10:22:56 +08:00
if ( SpatialMeshMaterial = = nullptr )
{
static ConstructorHelpers : : FObjectFinder < UMaterial > DefaultMaterialFinder ( TEXT ( " /Script/Engine.Material'/PICOOpenXR/PICOOpenXR/Materials/M_Wireframe.M_Wireframe' " ) ) ;
SpatialMeshMaterial = DefaultMaterialFinder . Object ;
}
2025-03-10 09:43:27 +08:00
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 )
{
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 - > AttachToComponent ( GetRootComponent ( ) , FAttachmentTransformRules : : KeepWorldTransform ) ;
SpatialMesh - > SetVisibility ( bSpatialMeshVisible ) ;
SpatialMesh - > SetCollisionEnabled ( CollisionType ) ;
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 ) ;
}
}
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 ) ;
}
}
}
bool ASpatialMeshActorPICO : : ClearMesh ( )
{
for ( const auto Pair : EntityToMeshMap )
{
if ( Pair . Value )
{
Pair . Value - > SetCollisionEnabled ( ECollisionEnabled : : NoCollision ) ;
Pair . Value - > DestroyComponent ( ) ;
}
}
EntityToMeshMap . Empty ( ) ;
MeshInfoQueue . Empty ( ) ;
FSpatialMeshExtensionPICO : : GetInstance ( ) - > ClearMeshProviderBuffer ( ) ;
return true ;
}
int32 ASpatialMeshActorPICO : : GetMeshNum ( )
{
return EntityToMeshMap . Num ( ) ;
}
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 )
{
2025-07-21 10:22:56 +08:00
TArray < int32 > TempIndices ;
2025-03-10 09:43:27 +08:00
TArray < FVector > TempVertices ;
2025-07-21 10:22:56 +08:00
TArray < FLinearColor > VertexColors ;
2025-03-10 09:43:27 +08:00
const UPICOOpenXRRuntimeSettings * Settings = GetDefault < UPICOOpenXRRuntimeSettings > ( ) ;
TArray < FVector > EmptyNormals ;
TArray < FVector2D > EmptyUV ;
2025-07-21 10:22:56 +08:00
TArray < FProcMeshTangent > EmptyTangents ;
SpatialMesh - > SetWorldLocationAndRotation ( MeshInfo . MeshPose . GetLocation ( ) , MeshInfo . MeshPose . GetRotation ( ) ) ;
2025-03-10 09:43:27 +08:00
if ( Settings - > bSemanticsAlignWithTriangle )
{
2025-07-21 10:22:56 +08:00
int32 ColorCount = MeshInfo . Semantics . Num ( ) ;
VertexColors . Reserve ( ColorCount ) ;
2025-03-10 09:43:27 +08:00
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 ) ;
2025-07-21 10:22:56 +08:00
FColor SemanticColor = GetColorBySceneLabel ( Semantic ) ;
VertexColors . Add ( SemanticColor ) ;
VertexColors . Add ( SemanticColor ) ;
VertexColors . Add ( SemanticColor ) ;
2025-03-10 09:43:27 +08:00
2025-07-21 10:22:56 +08:00
SpatialMesh - > AddIndexToSemanticLabel ( Index , Semantic ) ; }
2025-03-10 09:43:27 +08:00
}
}
}
else
{
TempVertices = MeshInfo . Vertices ;
2025-07-21 10:22:56 +08:00
TempIndices = MeshInfo . Indices ;
2025-03-10 09:43:27 +08:00
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 ] ] ;
2025-07-21 10:22:56 +08:00
SpatialMesh - > AddIndexToSemanticLabel ( Index , SemanticLabel ) ;
2025-03-10 09:43:27 +08:00
}
}
}
if ( TempVertices . Num ( ) & & TempIndices . Num ( ) )
{
2025-07-21 10:22:56 +08:00
//Create or update the mesh depending on if we've been created before
if ( SpatialMesh - > GetNumSections ( ) > 0 & & SpatialMesh - > IsEqualWithCached ( TempIndices ) )
{
SpatialMesh - > UpdateMeshSection_LinearColor ( 0 , TempVertices , EmptyNormals , EmptyUV , VertexColors , EmptyTangents ) ;
}
else
{
SpatialMesh - > CreateMeshSection_LinearColor ( 0 , TempVertices , TempIndices , EmptyNormals , EmptyUV , VertexColors , EmptyTangents , CollisionType ! = ECollisionEnabled : : Type : : NoCollision ) ;
SpatialMesh - > SetCachedIndices ( TempIndices ) ;
}
2025-03-10 09:43:27 +08:00
}
2025-07-21 10:22:56 +08:00
return true ;
2025-03-10 09:43:27 +08:00
}
return false ;
}