Giant_Beast_2025/Plugins/MetaXR/Source/MRUtilityKit/Private/MRUtilityKitDebugComponent.cpp

209 lines
5.9 KiB
C++

// Copyright (c) Meta Platforms, Inc. and affiliates.
#include "MRUtilityKitDebugComponent.h"
#include "MRUtilityKitTelemetry.h"
#include "MRUtilityKitSubsystem.h"
#include "MRUtilityKitAnchor.h"
#include "Kismet/KismetMathLibrary.h"
#include "IXRTrackingSystem.h"
#include "TextRenderComponent.h"
#include "Engine/World.h"
#include "Engine/GameInstance.h"
#include "Engine/Engine.h"
UMRUKDebugComponent::UMRUKDebugComponent()
{
PrimaryComponentTick.bCanEverTick = true;
}
void UMRUKDebugComponent::ShowAnchorAtRayHit(const FVector& Origin, const FVector& Direction)
{
if (!GizmoActorClass)
{
UE_LOG(LogMRUK, Warning, TEXT("Can not show anchor because no gizmo actor is set"));
return;
}
HideAnchor();
const auto Subsystem = GetOwner()->GetGameInstance()->GetSubsystem<UMRUKSubsystem>();
if (!Subsystem)
{
UE_LOG(LogMRUK, Warning, TEXT("Can not show anchor because there is no MRUtilityKit subsystem"));
return;
}
FMRUKHit Hit{};
FMRUKLabelFilter LabelFilter{};
auto Anchor = Subsystem->Raycast(Origin, Direction, 0.0, LabelFilter, Hit);
if (!Anchor)
{
return;
}
// Spawn Gizmo
if (!ActiveGizmoActor)
{
FActorSpawnParameters ActorSpawnParams;
ActorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
ActorSpawnParams.Owner = GetOwner();
ActiveGizmoActor = GetWorld()->SpawnActor(GizmoActorClass, nullptr, ActorSpawnParams);
}
else
{
ActiveGizmoActor->SetActorHiddenInGame(false);
}
ActiveGizmoActor->SetActorLocation(Hit.HitPosition);
ActiveGizmoActor->SetActorScale3D(GizmoScale);
ActiveGizmoActor->SetActorRotation(Anchor->GetActorRotation());
if (!TextActorClass)
{
UE_LOG(LogMRUK, Warning, TEXT("Can not show text at anchor because no text actor is set"));
return;
}
// Spawn Text
if (!ActiveTextActor)
{
FActorSpawnParameters ActorSpawnParams;
ActorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
ActorSpawnParams.Owner = GetOwner();
ActiveTextActor = GetWorld()->SpawnActor(TextActorClass, nullptr, ActorSpawnParams);
}
else
{
ActiveTextActor->SetActorHiddenInGame(false);
}
auto TextRenderComponent = ActiveTextActor->GetComponentByClass<UTextRenderComponent>();
FString Text;
for (int i = 0; i < Anchor->SemanticClassifications.Num(); ++i)
{
if (i != 0)
{
Text += ", ";
}
Text += Anchor->SemanticClassifications[i];
}
TextRenderComponent->SetText(FText::FromString(Text));
ActiveTextActor->SetActorLocation(Hit.HitPosition + (Hit.HitNormal * 20.0));
ActiveTextActor->SetActorScale3D(TextScale);
OrientTextActorToPlayer();
SetComponentTickEnabled(true);
}
void UMRUKDebugComponent::HideAnchor()
{
if (ActiveGizmoActor)
{
ActiveGizmoActor->SetActorHiddenInGame(true);
}
if (ActiveTextActor)
{
ActiveTextActor->SetActorHiddenInGame(true);
}
SetComponentTickEnabled(false);
}
void UMRUKDebugComponent::ShowAnchorSpaceAtRayHit(const FVector& Origin, const FVector& Direction)
{
const auto Subsystem = GetOwner()->GetGameInstance()->GetSubsystem<UMRUKSubsystem>();
if (!Subsystem)
{
UE_LOG(LogMRUK, Warning, TEXT("Can not show anchor because there is no MRUtilityKit subsystem"));
return;
}
FMRUKHit Hit{};
const auto Anchor = Subsystem->Raycast(Origin, Direction, 0.0, {}, Hit);
if (!Anchor)
{
return;
}
if (!ActiveAnchorSpaceActor || (ActiveAnchorSpaceActor && ActiveAnchorSpaceActor->GetParentActor() != Anchor))
{
static constexpr double DebugSpaceOffset = 0.5;
HideAnchorSpace();
FActorSpawnParameters ActorSpawnParams;
ActorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
ActorSpawnParams.Owner = Anchor;
ActiveAnchorSpaceActor = GetWorld()->SpawnActor<AActor>(ActorSpawnParams);
ActiveAnchorSpaceActor->SetRootComponent(NewObject<USceneComponent>(ActiveAnchorSpaceActor, TEXT("SceneComponent")));
ActiveAnchorSpaceActor->AttachToActor(Anchor, FAttachmentTransformRules::KeepRelativeTransform);
ActiveAnchorSpaceActor->GetRootComponent()->SetMobility(EComponentMobility::Movable);
const auto ProceduralMesh = NewObject<UProceduralMeshComponent>(ActiveAnchorSpaceActor, TEXT("DebugVolumePlane"));
Anchor->GenerateProceduralAnchorMesh(ProceduralMesh, {}, {}, true, false, DebugSpaceOffset);
ActiveAnchorSpaceActor->AddInstanceComponent(ProceduralMesh);
ProceduralMesh->SetupAttachment(ActiveAnchorSpaceActor->GetRootComponent());
ProceduralMesh->RegisterComponent();
}
}
void UMRUKDebugComponent::HideAnchorSpace()
{
if (ActiveAnchorSpaceActor)
{
ActiveAnchorSpaceActor->Destroy();
ActiveAnchorSpaceActor = nullptr;
}
}
void UMRUKDebugComponent::BeginPlay()
{
Super::BeginPlay();
OculusXRTelemetry::TScopedMarker<MRUKTelemetry::FLoadDebugComponentMarker> Event(static_cast<int>(GetTypeHash(this)));
SetComponentTickEnabled(false);
}
void UMRUKDebugComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
UE_LOG(LogTemp, Warning, TEXT("Ticking enabled"));
OrientTextActorToPlayer();
}
void UMRUKDebugComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
if (ActiveGizmoActor)
{
ActiveGizmoActor->Destroy();
ActiveGizmoActor = nullptr;
}
if (ActiveTextActor)
{
ActiveTextActor->Destroy();
ActiveTextActor = nullptr;
}
if (ActiveAnchorSpaceActor)
{
ActiveAnchorSpaceActor->Destroy();
ActiveAnchorSpaceActor = nullptr;
}
}
void UMRUKDebugComponent::OrientTextActorToPlayer() const
{
if (ActiveTextActor)
{
FQuat Orientation;
FVector Position(0.0);
GEngine->XRSystem->GetCurrentPose(IXRTrackingSystem::HMDDeviceId, Orientation, Position);
const auto TextForward = (Position - ActiveTextActor->GetActorLocation()).GetSafeNormal();
const auto TextUp = FVector::UpVector;
const auto TextRot = UKismetMathLibrary::MakeRotFromXZ(TextForward, TextUp);
ActiveTextActor->SetActorRotation(TextRot);
}
}