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

414 lines
14 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "PXR_SceneCapturesGenerator.h"
#include "JsonObjectConverter.h"
#include "PXR_EventManager.h"
#include "PXR_MRAsyncActions.h"
#include "PXR_MRFunctionLibrary.h"
#include "Algo/Transform.h"
#include "Engine/StaticMeshActor.h"
#include "Serialization/JsonWriter.h"
#include "Serialization/JsonSerializer.h"
#if WITH_EDITOR
#include "FileHelpers.h"
#endif
constexpr float WALL_WIDTH = 1.0f;
// Sets default values
APICOXRSceneCapturesGenerator::APICOXRSceneCapturesGenerator():
bEnableProceduralMeshForFloor(true),
ProceduralMeshMaterialForFloor(nullptr),
ProceduralMeshUVAdjustmentForFloor(),
bEnableProceduralMeshCollisionForFloor(false),
bEnableProceduralMeshForCeiling(false),
ProceduralMeshMaterialForCeiling(nullptr),
ProceduralMeshUVAdjustmentForCeiling(),
bEnableProceduralMeshCollisionForCeiling(false)
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
GenerateMaps =
{
{EPICOSemanticLabel::Wall, {}},
{EPICOSemanticLabel::Door, {}},
{EPICOSemanticLabel::Window, {}},
{EPICOSemanticLabel::Opening, {}},
{EPICOSemanticLabel::Table, {}},
{EPICOSemanticLabel::Sofa, {}},
{EPICOSemanticLabel::Chair, {}},
{EPICOSemanticLabel::Human, {}},
{EPICOSemanticLabel::Curtain, {}},
{EPICOSemanticLabel::Cabinet, {}},
{EPICOSemanticLabel::Bed, {}},
{EPICOSemanticLabel::Screen, {}},
{EPICOSemanticLabel::VirtualWall, {}},
};
}
// Called when the game starts or when spawned
void APICOXRSceneCapturesGenerator::BeginPlay()
{
Super::BeginPlay();
for (const auto& Scene:GenerateMaps)
{
if (Scene.Value.Actor)
{
SceneLoadInfo.SemanticFilter.Add(Scene.Key);
}
}
if (bEnableProceduralMeshForFloor)
{
SceneLoadInfo.SemanticFilter.Add(EPICOSemanticLabel::Floor);
}
if (bEnableProceduralMeshForCeiling)
{
SceneLoadInfo.SemanticFilter.Add(EPICOSemanticLabel::Ceiling);
}
}
// Called every frame
void APICOXRSceneCapturesGenerator::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void APICOXRSceneCapturesGenerator::LoadSceneDataAsync(const FPXRLoadSceneDataEventDelegate& OnLoadFinished)
{
SceneDataLoadDelegate = OnLoadFinished;
HandleSceneDataUpdatedEvent();
}
void APICOXRSceneCapturesGenerator::EnableAutoLoadingSceneData(bool InAutoLoadingEnabled)
{
if (InAutoLoadingEnabled)
{
if (!UPICOXRHMDFunctionLibrary::PXR_GetEventManager()->SceneCaptureDataUpdatedDelegate.Contains(this, GET_FUNCTION_NAME_CHECKED(APICOXRSceneCapturesGenerator, HandleSceneDataUpdatedEvent)))
{
UPICOXRHMDFunctionLibrary::PXR_GetEventManager()->SceneCaptureDataUpdatedDelegate.AddDynamic(this, &APICOXRSceneCapturesGenerator::HandleSceneDataUpdatedEvent);
}
}
else
{
if (UPICOXRHMDFunctionLibrary::PXR_GetEventManager()->SceneCaptureDataUpdatedDelegate.Contains(this, GET_FUNCTION_NAME_CHECKED(APICOXRSceneCapturesGenerator, HandleSceneDataUpdatedEvent)))
{
UPICOXRHMDFunctionLibrary::PXR_GetEventManager()->SceneCaptureDataUpdatedDelegate.RemoveDynamic(this, &APICOXRSceneCapturesGenerator::HandleSceneDataUpdatedEvent);
}
}
}
FVector APICOXRSceneCapturesGenerator::ConvertUnityPositionToUE(const FVector& InPosition, float WorldToMetersScale)
{
return FVector(InPosition.Z, InPosition.X, InPosition.Y) * WorldToMetersScale;
}
FQuat APICOXRSceneCapturesGenerator::ConvertUnityRotationToUE(const FQuat& InRotation)
{
return FQuat(InRotation.Z, InRotation.X, InRotation.Y, InRotation.W);
}
void APICOXRSceneCapturesGenerator::SpawnSceneCaptures_Offline(const FPICOMRSceneInfos_Offline& Scene_Offline)
{
float WorldToMetersScale = 100.0f;
if (GWorld != nullptr)
{
WorldToMetersScale=GWorld->GetWorldSettings()->WorldToMeters;
}
for (auto MRScene : Scene_Offline.OutSceneInfos)
{
FVector Location=ConvertUnityPositionToUE(MRScene.Position,WorldToMetersScale);
FQuat Quat=ConvertUnityRotationToUE(MRScene.Rotation);
FRotator Rotation=FRotator(Quat);
FTransform Transform=FTransform(Rotation,Location);
TArray<FVector> Vertices;
if (MRScene.PolygonVertices.Num())
{
Algo::Transform(MRScene.PolygonVertices, Vertices, [WorldToMetersScale](const auto& Vertex) { return FVector(-Vertex.Y, Vertex.X,0) * WorldToMetersScale; });
}
switch (MRScene.SemanticLabel) {
case EPICOSemanticLabel::Unknown:
break;
case EPICOSemanticLabel::Floor:
case EPICOSemanticLabel::Ceiling:
{
SpawnPolygonCapture(MRScene.SemanticLabel,Transform,Vertices);
}
break;
case EPICOSemanticLabel::Wall:
case EPICOSemanticLabel::Door:
case EPICOSemanticLabel::Window:
case EPICOSemanticLabel::Opening:
case EPICOSemanticLabel::VirtualWall:
{
FVector OriginScale=FVector(MRScene.Box2DInfo.Extent.Y*WorldToMetersScale,MRScene.Box2DInfo.Extent.X*WorldToMetersScale,WALL_WIDTH);
SpawnAndRescaling2DCapture(MRScene.SemanticLabel,Location,Rotation,OriginScale);
}
break;
case EPICOSemanticLabel::Table:
case EPICOSemanticLabel::Sofa:
case EPICOSemanticLabel::Chair:
case EPICOSemanticLabel::Human:
case EPICOSemanticLabel::Curtain:
case EPICOSemanticLabel::Cabinet:
case EPICOSemanticLabel::Bed:
case EPICOSemanticLabel::Stairway:
case EPICOSemanticLabel::Screen:
{
FVector OriginScale=ConvertUnityPositionToUE(MRScene.Box3DInfo.Extent,WorldToMetersScale);
SpawnAndRescaling3DCapture(MRScene.SemanticLabel,Location,Rotation,OriginScale);
}
break;
default:
break;
}
}
}
bool APICOXRSceneCapturesGenerator::SpawnAndRescaling2DCapture(EPICOSemanticLabel Label, const FVector& Location, const FRotator& Rotation,const FVector& OriginScale)
{
if (GenerateMaps.Contains(Label))
{
AActor* Box2DActor = GetWorld()->SpawnActor(GenerateMaps[Label].Actor);
if (Box2DActor != nullptr)
{
Box2DActor->Tags.AddUnique(FName(EnumToString(Label)));
SceneCaptures.Add(Box2DActor);
auto Root = Box2DActor->GetRootComponent();
Root->SetMobility(EComponentMobility::Movable);
Box2DActor->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
if (GenerateMaps[Label].ScalingMode == ESceneCaptureScalingMode::Stretch)
{
const auto Bounds = Box2DActor->CalculateComponentsBoundingBoxInLocalSpace(true);
const FVector ActorSize = Bounds.GetSize();
FVector FinalScale = OriginScale / ActorSize;
Box2DActor->SetActorScale3D(FinalScale);
}
Box2DActor->SetActorLocation(Location);
Box2DActor->SetActorRotation(Rotation);
return true;
}
}
return false;
}
bool APICOXRSceneCapturesGenerator::SpawnAndRescaling3DCapture(EPICOSemanticLabel Label, const FVector& Location, const FRotator& Rotation,const FVector& OriginScale)
{
if (GenerateMaps.Contains(Label))
{
AActor* Box3DActor = GetWorld()->SpawnActor(GenerateMaps[Label].Actor);
if (Box3DActor !=nullptr)
{
Box3DActor->Tags.AddUnique(FName(EnumToString(Label)));
SceneCaptures.Add(Box3DActor);
auto Root = Box3DActor->GetRootComponent();
Root->SetMobility(EComponentMobility::Movable);
Box3DActor->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
if (GenerateMaps[Label].ScalingMode==ESceneCaptureScalingMode::Stretch)
{
const auto Bounds = Box3DActor->CalculateComponentsBoundingBoxInLocalSpace(true);
const FVector Box3DActorSize = Bounds.GetSize();
FVector Scale=OriginScale/Box3DActorSize;
SetScaleBasedOnRotationAndOriginScale(Root,Scale,FQuat::Identity,FVector::OneVector);
}
Box3DActor->SetActorLocation(Location);
Box3DActor->SetActorRotation(Rotation);
return true;
}
}
return false;
}
bool APICOXRSceneCapturesGenerator::SpawnPolygonCapture(EPICOSemanticLabel Label, const FTransform& Transform, const TArray<FVector>& Vertices)
{
AActor* Actor = this->GetWorld()->SpawnActor<AActor>();
if (Actor != nullptr)
{
SceneCaptures.Add(Actor);
Actor->SetOwner(this);
Actor->Tags.AddUnique(FName(EnumToString(Label)));
Actor->SetRootComponent(NewObject<USceneComponent>(Actor, TEXT("Root")));
Actor->GetRootComponent()->SetMobility(EComponentMobility::Movable);
Actor->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
Actor->SetActorRelativeScale3D(FVector::OneVector);
Actor->SetActorTransform(Transform);
if(Label == EPICOSemanticLabel::Floor ? UPICOXRMRFunctionLibrary::PXR_CreateSceneBoundingPolygonWithUVAdjustment(Actor,!bEnableProceduralMeshCollisionForFloor,
false,ProceduralMeshUVAdjustmentForFloor,Transform,Vertices,ProceduralMeshMaterialForFloor)
:UPICOXRMRFunctionLibrary::PXR_CreateSceneBoundingPolygonWithUVAdjustment(Actor,!bEnableProceduralMeshCollisionForCeiling,
true,ProceduralMeshUVAdjustmentForCeiling,Transform,Vertices,ProceduralMeshMaterialForCeiling))
{
return true;
}
}
return false;
}
void APICOXRSceneCapturesGenerator::SpawnSceneCaptures(const TArray<FPICOMRSceneInfo>& SceneInfos)
{
for (auto SceneInfo : SceneInfos)
{
FRotator Rotation=FRotator(SceneInfo.ScenePose.GetRotation());
FVector Location=SceneInfo.ScenePose.GetLocation();
switch (SceneInfo.SceneType) {
case EPICOSceneType::BoundingBox2D:
{
FPICOBoundingBox2D Box2D;
UPICOXRMRFunctionLibrary::PXR_GetSceneBoundingBox2D(SceneInfo.UUID,Box2D);
Location+=Box2D.Center;
FVector OriginScale=FVector(WALL_WIDTH,Box2D.Extent.Width,Box2D.Extent.Height);
SpawnAndRescaling2DCapture(SceneInfo.Semantic,Location,Rotation,OriginScale);
}
break;
case EPICOSceneType::BoundingPolygon:
{
TArray<FVector> PolygonVertices;
UPICOXRMRFunctionLibrary::PXR_GetSceneBoundingPolygon(SceneInfo.UUID,PolygonVertices);
SpawnPolygonCapture(SceneInfo.Semantic,SceneInfo.ScenePose,PolygonVertices);
}
break;
case EPICOSceneType::BoundingBox3D:
{
FPICOBoundingBox3D Box3D;
UPICOXRMRFunctionLibrary::PXR_GetSceneBoundingBox3D(SceneInfo.UUID,Box3D);
FVector OriginScale=FVector(Box3D.Extent.Depth,Box3D.Extent.Width,Box3D.Extent.Height);
Location+=Box3D.Center.GetLocation();
SpawnAndRescaling3DCapture(SceneInfo.Semantic,Location,Rotation,OriginScale);
}
break;
}
}
}
bool APICOXRSceneCapturesGenerator::LoadOfflineSceneData(FString ImportPath, FPICOMRSceneInfos_Offline& OutSceneInfos)
{
OutSceneInfos.OutSceneInfos.Reset();
#if WITH_EDITOR
FPaths::NormalizeDirectoryName(ImportPath);
FString JsonString;
if (FFileHelper::LoadFileToString(JsonString, *ImportPath) )
{
FString Prefix = TEXT("{\r\n\"OutSceneInfos\":\r\n");
JsonString = Prefix + JsonString;
JsonString += "\r\n}";
TSharedRef< TJsonReader<> > JsonReader = TJsonReaderFactory<>::Create(JsonString);
TSharedPtr<FJsonObject> JsonComparisonReport;
if ( !FJsonSerializer::Deserialize(JsonReader, JsonComparisonReport) )
{
return false;
}
if ( FJsonObjectConverter::JsonObjectToUStruct(JsonComparisonReport.ToSharedRef(), &OutSceneInfos, 0, 0) )
{
if (OutSceneInfos.OutSceneInfos.Num())
{
UE_LOG(LogHMD, Display, TEXT("JsonObjectToUStruct Success"));
}
else
{
UE_LOG(LogHMD, Error, TEXT("JsonObjectToUStruct Failed"));
}
}
return true;
}
#endif
return false;
}
void APICOXRSceneCapturesGenerator::ClearSceneCaptures()
{
for (auto SceneCapture:SceneCaptures)
{
if(SceneCapture)
{
SceneCapture->Destroy();
}
}
SceneCaptures.Empty();
}
TArray<AActor*> APICOXRSceneCapturesGenerator::GetGeneratedActors()
{
return SceneCaptures;
}
// Determine the scaling values for the corresponding axes from the axis vectors and the original scaling vectors
FVector GetRotatedScale(const FVector& AxisX, const FVector& AxisY, const FVector& AxisZ, const FVector& OriginScale)
{
FVector RotatedScale;
RotatedScale.X = (FMath::Abs(AxisX.X) >= UE_INV_SQRT_2)? OriginScale.X : ((FMath::Abs(AxisX.Y) >= UE_INV_SQRT_2)? OriginScale.Y : OriginScale.Z);
RotatedScale.Y = (FMath::Abs(AxisY.X) >= UE_INV_SQRT_2)? OriginScale.X : ((FMath::Abs(AxisY.Y) >= UE_INV_SQRT_2)? OriginScale.Y : OriginScale.Z);
RotatedScale.Z = (FMath::Abs(AxisZ.X) >= UE_INV_SQRT_2)? OriginScale.X : ((FMath::Abs(AxisZ.Y) >= UE_INV_SQRT_2)? OriginScale.Y : OriginScale.Z);
return RotatedScale;
}
void APICOXRSceneCapturesGenerator::HandleSceneDataUpdatedEvent()
{
UPICORequestSceneCaptures_AsyncAction* RequestSceneCapturesAction = UPICORequestSceneCaptures_AsyncAction::PXR_RequestSceneCaptures_Async(SceneLoadInfo);
RequestSceneCapturesAction->OnSuccess.AddDynamic(this, &APICOXRSceneCapturesGenerator::HandleSceneLoadInfosEvent);
RequestSceneCapturesAction->Activate();
}
void APICOXRSceneCapturesGenerator::HandleSceneLoadInfosEvent(EPICOResult Result, const TArray<FPICOMRSceneInfo>& SceneInfos)
{
if (Result==EPICOResult::PXR_Success)
{
ClearSceneCaptures();
SpawnSceneCaptures(SceneInfos);
SceneDataLoadDelegate.ExecuteIfBound(Result);
}
}
void APICOXRSceneCapturesGenerator::SetScaleBasedOnRotationAndOriginScale(USceneComponent* SceneComponent, const FVector& OriginScale, const FQuat& BaseRotation, const FVector& BaseScale)
{
if (SceneComponent)
{
const auto RelativeRotation = SceneComponent->GetRelativeRotationCache().RotatorToQuat(SceneComponent->GetRelativeRotation());
const auto Rotation = BaseRotation * RelativeRotation;
const FVector RotatedXAxis = Rotation.GetAxisX();
const FVector RotatedYAxis = Rotation.GetAxisY();
const FVector RotatedZAxis = Rotation.GetAxisZ();
// Get the rotated scaling vector
FVector RotatedScale = GetRotatedScale(RotatedXAxis, RotatedYAxis, RotatedZAxis, OriginScale);
const FVector OldScale = SceneComponent->GetRelativeScale3D();
const FVector NewScale = BaseScale * RotatedScale * OldScale;
SceneComponent->SetRelativeScale3D(NewScale);
const FVector NewBaseScale = BaseScale * (OldScale / NewScale);
for (auto Child : SceneComponent->GetAttachChildren())
{
if (Child)
{
SetScaleBasedOnRotationAndOriginScale(Child, OriginScale, Rotation, NewBaseScale);
}
}
}
}