Skip to content
Snippets Groups Projects
Commit 0bf8d343 authored by David Gilbert's avatar David Gilbert :bug:
Browse files

refactor(cave): Removes dependency to RWTHVRToolkit.

This requires the removal of directly accessing the VRPawn in the CaveOverlay as well as splitting up the Utilities in Cluster and Toolkit specific ones.
CaveOverlay now also has implicitly more support for multiple MotionControllers, but needs to be tested.
parent 4ed00f8a
Branches
No related tags found
No related merge requests found
......@@ -14,6 +14,10 @@
"IsBetaVersion": false,
"Installed": false,
"EnabledByDefault": true,
"SupportedTargetPlatforms": [
"Win64",
"Linux"
],
"Modules": [
{
"Name": "RWTHVRCluster",
......@@ -26,10 +30,6 @@
}
],
"Plugins": [
{
"Name": "RWTHVRToolkit",
"Enabled": true
},
{
"Name": "nDisplay",
"Enabled": true,
......
......@@ -4,16 +4,15 @@
#include "EnhancedInputComponent.h"
#include "IDisplayCluster.h"
#include "MotionControllerComponent.h"
#include "Camera/CameraComponent.h"
#include "CAVEOverlay/DoorOverlayData.h"
#include "Camera/CameraComponent.h"
#include "Cluster/DisplayClusterClusterEvent.h"
#include "Cluster/IDisplayClusterClusterManager.h"
#include "Components/StaticMeshComponent.h"
#include "Engine/CollisionProfile.h"
#include "Logging/StructuredLog.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Pawn/RWTHVRPawn.h"
#include "Utility/RWTHVRUtilities.h"
#include "Utility/RWTHVRClusterUtilities.h"
DEFINE_LOG_CATEGORY(LogCAVEOverlay);
......@@ -50,8 +49,8 @@ ACAVEOverlayController::ACAVEOverlayController()
SetRootComponent(Root);
Tape = CreateMeshComponent("Tape", Root);
SignRightHand = CreateMeshComponent("SignRightHand", Root);
SignLeftHand = CreateMeshComponent("SignLeftHand", Root);
SignsStaticMeshComponents.Reserve(2);
MotionControllers.Reserve(2);
}
void ACAVEOverlayController::CycleDoorType()
......@@ -158,11 +157,11 @@ void ACAVEOverlayController::BeginPlay()
// Not sure which place would be best...
const bool bValidPC = PC && PC->GetLocalPlayer();
if (!bValidPC || !URWTHVRUtilities::IsRoomMountedMode())
if (!bValidPC || !URWTHVRClusterUtilities::IsRoomMountedMode())
return;
// Input config
if (URWTHVRUtilities::IsPrimaryNode())
if (URWTHVRClusterUtilities::IsPrimaryNode())
{
if (CycleDoorTypeInputAction == nullptr)
{
......@@ -219,9 +218,35 @@ void ACAVEOverlayController::BeginPlay()
Overlay->CornerText->SetText(FText::FromString(""));
// Get the pawn so we can have access to head and hand positions
VRPawn = Cast<ARWTHVRPawn>(PC->GetPawnOrSpectator());
if (VRPawn)
if (const auto* VRPawn = Cast<APawn>(PC->GetPawnOrSpectator()))
{
PawnCamera = VRPawn->GetComponentByClass<UCameraComponent>();
auto FoundMotionControllers = VRPawn->K2_GetComponentsByClass(UMotionControllerComponent::StaticClass());
for (const auto FoundMotionController : FoundMotionControllers)
{
if (auto* MC = Cast<UMotionControllerComponent>(FoundMotionController);
MC && MC->MotionSource != EName::None)
{
// Create new static mesh for them
auto* SignStaticMeshComp = NewObject<UStaticMeshComponent>();
SignStaticMeshComp->SetStaticMesh(SignStaticMesh);
SignStaticMeshComp->SetupAttachment(RootComponent);
SignStaticMeshComp->RegisterComponent();
MotionControllers.Add(MC);
SignsStaticMeshComponents.Add(SignStaticMeshComp);
SignsMIDs.Add(SignStaticMeshComp->CreateAndSetMaterialInstanceDynamic(0));
}
}
if (MotionControllers.Num() != 2)
{
UE_LOGFMT(LogCAVEOverlay, Display,
"Found unexpected number of MotionControllers on Pawn. Expected 2, found {Number}. This might "
"lead to weird results",
MotionControllers.Num());
}
// we're good to go!
bInitialized = true;
}
......@@ -230,10 +255,8 @@ void ACAVEOverlayController::BeginPlay()
UE_LOGFMT(LogCAVEOverlay, Error, "No VirtualRealityPawn found which we could attach to!");
}
// Create dynamic materials at runtime
// Create dynamic material for tape
TapeMaterialDynamic = Tape->CreateDynamicMaterialInstance(0);
RightSignMaterialDynamic = SignRightHand->CreateDynamicMaterialInstance(0);
LeftSignMaterialDynamic = SignLeftHand->CreateDynamicMaterialInstance(0);
UE_LOGFMT(LogCAVEOverlay, Display, "CaveOverlay Initialization was successfull.");
}
......@@ -317,41 +340,46 @@ void ACAVEOverlayController::Tick(float DeltaTime)
}
// Head/Tape Logic
const FVector HeadPosition = VRPawn->HeadCameraComponent->GetRelativeTransform().GetLocation();
const bool bHeadIsCloseToWall =
FMath::IsWithinInclusive(HeadPosition.GetAbsMax(), WallDistance - WallCloseDistance, WallDistance);
// Only show the tape when close to a wall and not within the door opening
if (bHeadIsCloseToWall && !PositionInDoorOpening(HeadPosition))
if (PawnCamera)
{
Tape->SetVisibility(true);
const FVector HeadPosition = PawnCamera->GetRelativeTransform().GetLocation();
const bool bHeadIsCloseToWall =
FMath::IsWithinInclusive(HeadPosition.GetAbsMax(), WallDistance - WallCloseDistance, WallDistance);
// Offset the tape in z direction to always be at head height
Tape->SetRelativeLocation(HeadPosition * FVector(0, 0, 1));
TapeMaterialDynamic->SetScalarParameterValue("BarrierOpacity", CalculateOpacityFromPosition(HeadPosition));
if (FMath::IsWithin(FVector2D(HeadPosition).GetAbsMax(), WallDistance - WallWarningDistance, WallDistance))
// Only show the tape when close to a wall and not within the door opening
if (bHeadIsCloseToWall && !PositionInDoorOpening(HeadPosition))
{
// in warning distance == red tape
TapeMaterialDynamic->SetVectorParameterValue("StripeColor", FVector(1, 0, 0));
Tape->SetVisibility(true);
// Offset the tape in z direction to always be at head height
Tape->SetRelativeLocation(HeadPosition * FVector(0, 0, 1));
TapeMaterialDynamic->SetScalarParameterValue("BarrierOpacity", CalculateOpacityFromPosition(HeadPosition));
if (FMath::IsWithin(FVector2D(HeadPosition).GetAbsMax(), WallDistance - WallWarningDistance, WallDistance))
{
// in warning distance == red tape
TapeMaterialDynamic->SetVectorParameterValue("StripeColor", FVector(1, 0, 0));
}
else
{
// otherwise we're just yellow
TapeMaterialDynamic->SetVectorParameterValue("StripeColor", FVector(1, 1, 0));
}
}
else
{
// otherwise we're just yellow
TapeMaterialDynamic->SetVectorParameterValue("StripeColor", FVector(1, 1, 0));
Tape->SetVisibility(false);
}
}
else
{
Tape->SetVisibility(false);
}
// Hand Logic
const FVector RightPosition = VRPawn->RightHand->GetRelativeTransform().GetLocation();
const FVector LeftPosition = VRPawn->LeftHand->GetRelativeTransform().GetLocation();
for (int i = 0; i < MotionControllers.Num(); i++)
{
const FVector HandPosition = MotionControllers[i]->GetRelativeLocation();
// Set the position rotation, opacity, visibility of the hand warning signs.
SetSignsForHand(SignRightHand, RightPosition, RightSignMaterialDynamic);
SetSignsForHand(SignLeftHand, LeftPosition, LeftSignMaterialDynamic);
// Set the position rotation, opacity, visibility of the hand warning signs.
SetSignsForHand(SignsStaticMeshComponents[i], HandPosition, SignsMIDs[i]);
}
}
......@@ -4,8 +4,7 @@
#include "CaveSetup.h"
#include "Logging/StructuredLog.h"
#include "Utility/RWTHVRUtilities.h"
#include "Utility/RWTHVRClusterUtilities.h"
// Sets default values
ACaveSetup::ACaveSetup()
......@@ -22,7 +21,7 @@ void ACaveSetup::BeginPlay()
{
Super::BeginPlay();
if (!URWTHVRUtilities::IsRoomMountedMode())
if (!URWTHVRClusterUtilities::IsRoomMountedMode())
{
return;
}
......@@ -41,7 +40,7 @@ void ACaveSetup::BeginPlay()
// Apply the DTrack LiveLink Preset. Only do this if we are the primaryNode
if (URWTHVRUtilities::IsPrimaryNode())
if (URWTHVRClusterUtilities::IsPrimaryNode())
{
if (LiveLinkPresetToApplyOnCave && LiveLinkPresetToApplyOnCave->IsValidLowLevelFast())
{
......
#include "Utility/RWTHVRClusterUtilities.h"
#include "DisplayClusterConfigurationTypes.h"
#include "DisplayClusterRootActor.h"
#include "IDisplayCluster.h"
#include "Cluster/IDisplayClusterClusterManager.h"
#include "Components/DisplayClusterCameraComponent.h"
#include "Config/IDisplayClusterConfigManager.h"
#include "Engine/Engine.h"
#include "Engine/LocalPlayer.h"
#include "Game/IDisplayClusterGameManager.h"
DEFINE_LOG_CATEGORY(ClusterPlugin);
bool URWTHVRClusterUtilities::IsRoomMountedMode()
{
return IDisplayCluster::Get().GetOperationMode() == EDisplayClusterOperationMode::Cluster;
}
bool URWTHVRClusterUtilities::IsCave()
{
if (!IsRoomMountedMode())
return false;
const UDisplayClusterConfigurationData* ClusterConfig = IDisplayCluster::Get().GetConfigMgr()->GetConfig();
return ClusterConfig->CustomParameters.Contains("Hardware_Platform") &&
ClusterConfig->CustomParameters.Find("Hardware_Platform")->Equals("aixcave", ESearchCase::IgnoreCase);
}
bool URWTHVRClusterUtilities::IsRolv()
{
if (!IsRoomMountedMode())
return false;
const UDisplayClusterConfigurationData* ClusterConfig = IDisplayCluster::Get().GetConfigMgr()->GetConfig();
return ClusterConfig->CustomParameters.Contains("Hardware_Platform") &&
ClusterConfig->CustomParameters.Find("Hardware_Platform")->Equals("ROLV", ESearchCase::IgnoreCase);
}
/* Return true on the Primary in cluster mode and in a normal desktop session. Otherwise false */
bool URWTHVRClusterUtilities::IsPrimaryNode()
{
if (!IDisplayCluster::IsAvailable())
{
return true;
}
IDisplayClusterClusterManager* Manager = IDisplayCluster::Get().GetClusterMgr();
if (Manager == nullptr)
{
return true; // if we are not in cluster mode, we are always the primary node
}
return Manager->IsPrimary() || !Manager->IsSecondary();
}
bool URWTHVRClusterUtilities::IsSecondaryNode() { return !IsPrimaryNode(); }
FString URWTHVRClusterUtilities::GetNodeName()
{
return IsRoomMountedMode() ? IDisplayCluster::Get().GetClusterMgr()->GetNodeId() : FString(TEXT("Localhost"));
}
float URWTHVRClusterUtilities::GetEyeDistance()
{
const ADisplayClusterRootActor* RootActor = IDisplayCluster::Get().GetGameMgr()->GetRootActor();
return (RootActor) ? RootActor->GetDefaultCamera()->GetInterpupillaryDistance() : 0.0f;
}
EDisplayClusterEyeStereoOffset URWTHVRClusterUtilities::GetNodeEyeType()
{
const ADisplayClusterRootActor* RootActor = IDisplayCluster::Get().GetGameMgr()->GetRootActor();
return (RootActor) ? RootActor->GetDefaultCamera()->GetStereoOffset() : EDisplayClusterEyeStereoOffset::None;
}
USceneComponent* URWTHVRClusterUtilities::GetClusterComponent(const FString& Name)
{
const ADisplayClusterRootActor* RootActor = IDisplayCluster::Get().GetGameMgr()->GetRootActor();
return (RootActor) ? RootActor->GetComponentByName<USceneComponent>(Name) : nullptr;
}
USceneComponent* URWTHVRClusterUtilities::GetNamedClusterComponent(const ENamedClusterComponent& Component)
{
switch (Component)
{
case ENamedClusterComponent::NCC_CAVE_ORIGIN:
return GetClusterComponent("cave_origin");
case ENamedClusterComponent::NCC_CAVE_CENTER:
return GetClusterComponent("cave_center");
case ENamedClusterComponent::NCC_CAVE_LHT:
return GetClusterComponent("left_hand_target");
case ENamedClusterComponent::NCC_CAVE_RHT:
return GetClusterComponent("right_hand_target");
case ENamedClusterComponent::NCC_SHUTTERGLASSES:
return GetClusterComponent("shutter_glasses");
case ENamedClusterComponent::NCC_ROLV_ORIGIN:
return GetClusterComponent("rolv_origin");
case ENamedClusterComponent::NCC_FLYSTICK:
return GetClusterComponent("flystick");
case ENamedClusterComponent::NCC_CALIBRATIO:
return GetClusterComponent("calibratio");
case ENamedClusterComponent::NCC_TRACKING_ORIGIN:
USceneComponent* Result;
if ((Result = GetClusterComponent("cave_origin")))
return Result;
if ((Result = GetClusterComponent("rolv_origin")))
return Result;
if ((Result = GetClusterComponent("tdw_origin_floor")))
return Result;
return nullptr;
default:
return nullptr;
}
}
......@@ -8,7 +8,10 @@
#include "CAVEOverlayController.generated.h"
class UMotionControllerComponent;
class UCameraComponent;
class ARWTHVRPawn;
DECLARE_LOG_CATEGORY_EXTERN(LogCAVEOverlay, Log, All);
/**
......@@ -91,9 +94,12 @@ private:
// Only calculate positions and material values when we're fully initialized.
bool bInitialized = false;
// Reference to the currently active pawn that we're tracking positions of.
// Reference to the currently active pawn's camera and hands that we're tracking positions of.
UPROPERTY()
UCameraComponent* PawnCamera;
UPROPERTY()
ARWTHVRPawn* VRPawn;
TArray<UMotionControllerComponent*> MotionControllers;
// Cluster Events
FOnClusterEventJsonListener ClusterEventListenerDelegate;
......@@ -114,13 +120,17 @@ public:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true"))
UStaticMeshComponent* Tape;
// Right Hand Sign Static Mesh component. Reference to static mesh needs to be set in the corresponding BP.
// Right Hand Sign Static Mesh Reference
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true"))
UStaticMeshComponent* SignRightHand;
UStaticMesh* SignStaticMesh;
// Left Hand Sign Static Mesh component. Reference to static mesh needs to be set in the corresponding BP.
// Static Mesh Components for all tracked MotionControllers
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true"))
UStaticMeshComponent* SignLeftHand;
TArray<UStaticMeshComponent*> SignsStaticMeshComponents;
// Static Mesh Components for all tracked MotionControllers
UPROPERTY()
TArray<UMaterialInstanceDynamic*> SignsMIDs;
// UI Overlay
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "CAVEOverlay")
......@@ -136,10 +146,4 @@ public:
// Dynamic Materials to control opacity
UPROPERTY()
UMaterialInstanceDynamic* TapeMaterialDynamic;
UPROPERTY()
UMaterialInstanceDynamic* RightSignMaterialDynamic;
UPROPERTY()
UMaterialInstanceDynamic* LeftSignMaterialDynamic;
};
#pragma once
#include "CoreMinimal.h"
#include "Components/DisplayClusterCameraComponent.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "UObject/ConstructorHelpers.h"
#include "RWTHVRClusterUtilities.generated.h"
/**
* Custom log category for all ClusterPlugin related components
*/
DECLARE_LOG_CATEGORY_EXTERN(ClusterPlugin, Log, All);
UENUM(BlueprintType)
enum class ENamedClusterComponent : uint8
{
/* CAVE Specific */
NCC_CAVE_ORIGIN UMETA(DisplayName = "CAVE Origin"),
NCC_CAVE_CENTER UMETA(DisplayName = "CAVE Center"),
NCC_CAVE_LHT UMETA(DisplayName = "CAVE Left Hand Target"),
NCC_CAVE_RHT UMETA(DisplayName = "CAVE Right Hand Target"),
/* ROLV Specific */
NCC_ROLV_ORIGIN UMETA(DisplayName = "ROLV Origin"),
/* Non Specific */
NCC_CALIBRATIO UMETA(DisplayName = "Calibratio Motion to Photon Measurement Device"),
NCC_SHUTTERGLASSES UMETA(DisplayName = "CAVE/ROLV/TDW Shutter Glasses"),
NCC_FLYSTICK UMETA(DisplayName = "CAVE/ROLV/TDW Flystick"),
NCC_TRACKING_ORIGIN UMETA(DisplayName = "CAVE/ROLV/TDW Origin")
};
UCLASS()
class RWTHVRCLUSTER_API URWTHVRClusterUtilities : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
static bool IsRoomMountedMode();
UFUNCTION(BlueprintPure, Category = "DisplayCluster|Platform")
static bool IsCave();
UFUNCTION(BlueprintPure, Category = "DisplayCluster|Platform")
static bool IsRolv();
UFUNCTION(BlueprintPure, Category = "DisplayCluster")
static bool IsPrimaryNode();
UFUNCTION(BlueprintPure, Category = "DisplayCluster")
static bool IsSecondaryNode();
UFUNCTION(BlueprintPure, Category = "DisplayCluster")
static FString GetNodeName();
/* Distance in meters */
UFUNCTION(BlueprintPure, Category = "DisplayCluster")
static float GetEyeDistance();
UFUNCTION(BlueprintPure, Category = "DisplayCluster")
static EDisplayClusterEyeStereoOffset GetNodeEyeType();
//Get Component of Display Cluster by it's name, which is specified in the nDisplay config
UE_DEPRECATED(5.4, "GetClusterComponent has been removed because it is obsolete.")
UFUNCTION(BlueprintPure, BlueprintCallable, Category = "DisplayCluster", meta = (DeprecatedFunction))
static USceneComponent* GetClusterComponent(const FString& Name);
UE_DEPRECATED(5.4, "GetNamedClusterComponent has been removed because it is obsolete.")
UFUNCTION(BlueprintPure, BlueprintCallable, Category = "DisplayCluster", meta = (DeprecatedFunction))
static USceneComponent* GetNamedClusterComponent(const ENamedClusterComponent& Component);
};
......@@ -26,8 +26,8 @@ public class RWTHVRCluster : ModuleRules
"Slate",
"SlateCore",
"LiveLink",
"DisplayCluster",
"RWTHVRToolkit"
"HeadMountedDisplay", // required for MotionControllerComp
"DisplayCluster"
}
);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment