diff --git a/Source/DisplayClusterExtensions/Private/VirtualRealityPawn.cpp b/Source/DisplayClusterExtensions/Private/VirtualRealityPawn.cpp index 1c22a257e1704155943a67f47d1afe8a2dc957c9..c9c719b38331a72d7f8f1bcadd57b4f2dc95c924 100644 --- a/Source/DisplayClusterExtensions/Private/VirtualRealityPawn.cpp +++ b/Source/DisplayClusterExtensions/Private/VirtualRealityPawn.cpp @@ -1,6 +1,8 @@ #include "VirtualRealityPawn.h" +#include "Camera/CameraComponent.h" #include "Cluster/IDisplayClusterClusterManager.h" +#include "Engine/Engine.h" #include "Engine/World.h" #include "Game/IDisplayClusterGameManager.h" #include "GameFramework/InputSettings.h" @@ -8,18 +10,14 @@ #include "Kismet/GameplayStatics.h" #include "DisplayClusterSettings.h" #include "IDisplayCluster.h" - -#include "IDisplayClusterConfigManager.h" -#include "IXRTrackingSystem.h" -#include "Engine/Engine.h" -#include "Camera/CameraComponent.h" +#include "VirtualRealityUtilities.h" AVirtualRealityPawn::AVirtualRealityPawn(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { bUseControllerRotationYaw = true; bUseControllerRotationPitch = true; bUseControllerRotationRoll = true; - + AutoPossessPlayer = EAutoReceiveInput::Player0; // Necessary for receiving motion controller events. Movement = CreateDefaultSubobject<UFloatingPawnMovement>(TEXT("Movement")); @@ -31,6 +29,10 @@ AVirtualRealityPawn::AVirtualRealityPawn(const FObjectInitializer& ObjectInitial RotatingMovement->PivotTranslation = FVector::ZeroVector; RotatingMovement->RotationRate = FRotator::ZeroRotator; + Head = CreateDefaultSubobject<USceneComponent>(TEXT("Head")); + RightHand = CreateDefaultSubobject<USceneComponent>(TEXT("RightHand")); + LeftHand = CreateDefaultSubobject<USceneComponent>(TEXT("LeftHand")); + HmdLeftMotionController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("HmdLeftMotionController")); HmdLeftMotionController->SetupAttachment(RootComponent); HmdLeftMotionController->SetTrackingSource(EControllerHand::Left); @@ -47,7 +49,7 @@ AVirtualRealityPawn::AVirtualRealityPawn(const FObjectInitializer& ObjectInitial void AVirtualRealityPawn::OnForward_Implementation(float Value) { // Check if this function triggers correctly on ROLV. - if (RightHand && (NavigationMode == EVRNavigationModes::nav_mode_fly || IsDesktopMode() || IsHeadMountedMode())) + if (RightHand && (NavigationMode == EVRNavigationModes::nav_mode_fly || UVirtualRealityUtilities::IsDesktopMode() || UVirtualRealityUtilities::IsHeadMountedMode())) { AddMovementInput(RightHand->GetForwardVector(), Value); } @@ -55,7 +57,7 @@ void AVirtualRealityPawn::OnForward_Implementation(float Value) void AVirtualRealityPawn::OnRight_Implementation(float Value) { - if (RightHand && (NavigationMode == EVRNavigationModes::nav_mode_fly || IsDesktopMode() || IsHeadMountedMode())) + if (RightHand && (NavigationMode == EVRNavigationModes::nav_mode_fly || UVirtualRealityUtilities::IsDesktopMode() || UVirtualRealityUtilities::IsHeadMountedMode())) { AddMovementInput(RightHand->GetRightVector(), Value); } @@ -81,7 +83,7 @@ void AVirtualRealityPawn::OnTurnRate_Implementation(float Rate) void AVirtualRealityPawn::OnLookUpRate_Implementation(float Rate) { - if (IsRoomMountedMode()) + if (UVirtualRealityUtilities::IsRoomMountedMode()) { // User-centered projection causes simulation sickness on look up interaction hence not implemented. } @@ -99,31 +101,6 @@ void AVirtualRealityPawn::OnAction_Implementation(bool Pressed, int32 Index) { } -bool AVirtualRealityPawn::IsDesktopMode() -{ - return !IsRoomMountedMode() && !IsHeadMountedMode(); -} - -bool AVirtualRealityPawn::IsRoomMountedMode() -{ - return IDisplayCluster::Get().GetOperationMode() == EDisplayClusterOperationMode::Cluster; -} - -bool AVirtualRealityPawn::IsHeadMountedMode() -{ - return GEngine->XRSystem.IsValid() && GEngine->XRSystem->IsHeadTrackingAllowed(); -} - -FString AVirtualRealityPawn::GetNodeName() -{ - return IsRoomMountedMode() ? IDisplayCluster::Get().GetClusterMgr()->GetNodeId() : FString(TEXT("Localhost")); -} - -float AVirtualRealityPawn::GetEyeDistance() -{ - return IDisplayCluster::Get().GetConfigMgr()->GetConfigStereo().EyeDist; -} - float AVirtualRealityPawn::GetBaseTurnRate() const { return BaseTurnRate; @@ -149,6 +126,16 @@ UDisplayClusterSceneComponent* AVirtualRealityPawn::GetFlystickComponent() return Flystick; } +UDisplayClusterSceneComponent* AVirtualRealityPawn::GetRightHandtargetComponent() +{ + return RightHandTarget; +} + +UDisplayClusterSceneComponent* AVirtualRealityPawn::GetLeftHandtargetComponent() +{ + return LeftHandTarget; +} + UMotionControllerComponent* AVirtualRealityPawn::GetHmdLeftMotionControllerComponent() { return HmdLeftMotionController; @@ -174,9 +161,9 @@ USceneComponent* AVirtualRealityPawn::GetRightHandComponent() return RightHand; } -USceneComponent* AVirtualRealityPawn::GetCaveOriginComponent() +USceneComponent* AVirtualRealityPawn::GetTrackingOriginComponent() { - return CaveOrigin; + return TrackingOrigin; } USceneComponent* AVirtualRealityPawn::GetCaveCenterComponent() @@ -189,9 +176,22 @@ USceneComponent* AVirtualRealityPawn::GetShutterGlassesComponent() return ShutterGlasses; } -UDisplayClusterSceneComponent* AVirtualRealityPawn::GetClusterComponent(const FString& Name) +void AVirtualRealityPawn::ClusterExecute(const FString& Command) +{ + FDisplayClusterClusterEvent event; + event.Name = "NDisplayCMD: " + Command; + event.Type = "NDisplayCMD"; + event.Category = "VRPawn"; + event.Parameters.Add("Command", Command); + IDisplayCluster::Get().GetClusterMgr()->EmitClusterEvent(event, false); +} + +void AVirtualRealityPawn::HandleClusterEvent(const FDisplayClusterClusterEvent& Event) { - return IDisplayCluster::Get().GetGameMgr()->GetNodeById(Name); + if (Event.Category.Equals("VRPawn") && Event.Type.Equals("NDisplayCMD") && Event.Parameters.Contains("Command")) + { + GEngine->Exec(GetWorld(), *Event.Parameters["Command"]); + } } void AVirtualRealityPawn::BeginPlay() @@ -211,41 +211,76 @@ void AVirtualRealityPawn::BeginPlay() BaseTurnRate = Settings->RotationSpeed; } - if (IsRoomMountedMode()) + if (UVirtualRealityUtilities::IsRoomMountedMode()) { UInputSettings::GetInputSettings()->RemoveAxisMapping(FInputAxisKeyMapping("TurnRate", EKeys::MouseX)); UInputSettings::GetInputSettings()->RemoveAxisMapping(FInputAxisKeyMapping("LookUpRate", EKeys::MouseY)); - InitComponentReferences(); - - RootComponent->SetWorldLocation(FVector(0, 2, 0), false, nullptr, ETeleportType::None); + InitRoomMountedComponentReferences(); } - else if (IsHeadMountedMode()) + else if (UVirtualRealityUtilities::IsHeadMountedMode()) { UInputSettings::GetInputSettings()->RemoveAxisMapping(FInputAxisKeyMapping("TurnRate", EKeys::MouseX)); UInputSettings::GetInputSettings()->RemoveAxisMapping(FInputAxisKeyMapping("LookUpRate", EKeys::MouseY)); - HmdLeftMotionController->SetVisibility(true); - HmdRightMotionController->SetVisibility(true); + HmdLeftMotionController->SetVisibility(ShowHMDControllers); + HmdRightMotionController->SetVisibility(ShowHMDControllers); - LeftHand = HmdLeftMotionController; - RightHand = HmdRightMotionController; - Head = GetCameraComponent(); + LeftHand->AttachToComponent(HmdLeftMotionController, FAttachmentTransformRules::KeepRelativeTransform); + RightHand->AttachToComponent(HmdRightMotionController, FAttachmentTransformRules::KeepRelativeTransform); + Head->AttachToComponent(GetCameraComponent(), FAttachmentTransformRules::KeepRelativeTransform); } else //Desktop { - LeftHand = RootComponent; - RightHand = RootComponent; - Head = GetCameraComponent(); + Head->AttachToComponent(GetCameraComponent(), FAttachmentTransformRules::KeepRelativeTransform); + + //also attach the hands to the camera component so we can use them for interaction + LeftHand->AttachToComponent(GetCameraComponent(), FAttachmentTransformRules::KeepRelativeTransform); + RightHand->AttachToComponent(GetCameraComponent(), FAttachmentTransformRules::KeepRelativeTransform); + + + //move to eyelevel + GetCameraComponent()->SetRelativeLocation(FVector(0, 0, 160)); + } + + //In ADisplayClusterPawn::BeginPlay() input is disabled on all slaves, so we cannot react to button presses, e.g. on the flystick correctly. + //Therefore, we activate it again: + UWorld* World = GetWorld(); + if (World) + { + APlayerController* PlayerController = World->GetFirstPlayerController(); + if (PlayerController) + { + this->EnableInput(PlayerController); + } + } + + // Register cluster event listeners + IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr(); + if (ClusterManager && !ClusterEventListenerDelegate.IsBound()) + { + ClusterEventListenerDelegate = FOnClusterEventListener::CreateUObject(this, &AVirtualRealityPawn::HandleClusterEvent); + ClusterManager->AddClusterEventListener(ClusterEventListenerDelegate); } } +void AVirtualRealityPawn::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr(); + if (ClusterManager && ClusterEventListenerDelegate.IsBound()) + { + ClusterManager->RemoveClusterEventListener(ClusterEventListenerDelegate); + } + + Super::EndPlay(EndPlayReason); +} + void AVirtualRealityPawn::Tick(float DeltaSeconds) { Super::Tick(DeltaSeconds); //Flystick might not be available at start, hence is checked every frame. - InitComponentReferences(); + InitRoomMountedComponentReferences(); } void AVirtualRealityPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) @@ -265,47 +300,37 @@ UPawnMovementComponent* AVirtualRealityPawn::GetMovementComponent() const return Movement; } -void AVirtualRealityPawn::InitComponentReferences() +void AVirtualRealityPawn::InitRoomMountedComponentReferences() { - if (!IsRoomMountedMode()) return; - if (!CaveOrigin) CaveOrigin = GetClusterComponent("cave_origin"); - if (!CaveCenter) CaveCenter = GetClusterComponent("cave_center"); + if (!UVirtualRealityUtilities::IsRoomMountedMode()) return; + + //check whether the nodes already exist (otherwise GetClusterComponent() returns nullptr and prints a warning) and assign them + if (!TrackingOrigin) TrackingOrigin = UVirtualRealityUtilities::GetClusterComponent("cave_origin"); + if (!TrackingOrigin) TrackingOrigin = UVirtualRealityUtilities::GetClusterComponent("rolv_origin"); + if (!CaveCenter) CaveCenter = UVirtualRealityUtilities::GetClusterComponent("cave_center"); if (!ShutterGlasses) { - ShutterGlasses = GetClusterComponent("shutter_glasses"); - Head = ShutterGlasses; + ShutterGlasses = UVirtualRealityUtilities::GetClusterComponent("shutter_glasses"); + Head->AttachToComponent(ShutterGlasses, FAttachmentTransformRules::KeepRelativeTransform); } if (!Flystick) { - Flystick = GetClusterComponent("flystick"); - - LeftHand = Flystick; - RightHand = Flystick; + Flystick = UVirtualRealityUtilities::GetClusterComponent("flystick"); + if (AttachRightHandInCAVE == EAttachementType::AT_FLYSTICK) + RightHand->AttachToComponent(Flystick, FAttachmentTransformRules::KeepRelativeTransform); + if (AttachLeftHandInCAVE == EAttachementType::AT_FLYSTICK) + LeftHand->AttachToComponent(Flystick, FAttachmentTransformRules::KeepRelativeTransform); } -} - -EEyeType AVirtualRealityPawn::GetNodeEyeType() { - FDisplayClusterConfigClusterNode CurrentNodeConfig; - IDisplayCluster::Get().GetConfigMgr()->GetClusterNode(GetNodeName(), CurrentNodeConfig); - - FString s = CurrentNodeConfig.ToString(); - - if (s.Contains("mono_eye")) { - TArray<FString> stringArray; - int32 count = s.ParseIntoArray(stringArray, TEXT(",")); - for (int x = 0; x < count; x++) { - if (!stringArray[x].Contains("mono_eye")) continue; - if (stringArray[x].Contains("left")) { - return EEyeType::ET_STEREO_LEFT; - } - if (stringArray[x].Contains("right")) { - return EEyeType::ET_STEREO_RIGHT; - } - } + if (!LeftHandTarget) + { + LeftHandTarget = UVirtualRealityUtilities::GetClusterComponent("left_hand_target"); + if (AttachLeftHandInCAVE == EAttachementType::AT_HANDTARGET) + LeftHand->AttachToComponent(LeftHandTarget, FAttachmentTransformRules::KeepRelativeTransform); } - else { - return EEyeType::ET_MONO; + if (!RightHandTarget) + { + RightHandTarget = UVirtualRealityUtilities::GetClusterComponent("right_hand_target"); + if (AttachRightHandInCAVE == EAttachementType::AT_HANDTARGET) + RightHand->AttachToComponent(RightHandTarget, FAttachmentTransformRules::KeepRelativeTransform); } - return EEyeType::ET_MONO; } - diff --git a/Source/DisplayClusterExtensions/Private/VirtualRealityUtilities.cpp b/Source/DisplayClusterExtensions/Private/VirtualRealityUtilities.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30a85dd360f560bdc7772418b0e3a653b2a2dfb8 --- /dev/null +++ b/Source/DisplayClusterExtensions/Private/VirtualRealityUtilities.cpp @@ -0,0 +1,66 @@ +#include "VirtualRealityUtilities.h" + +#include "Cluster/IDisplayClusterClusterManager.h" +#include "Engine/Engine.h" +#include "Game/IDisplayClusterGameManager.h" +#include "IDisplayCluster.h" +#include "IDisplayClusterConfigManager.h" +#include "IXRTrackingSystem.h" + +bool UVirtualRealityUtilities::IsDesktopMode() +{ + return !IsRoomMountedMode() && !IsHeadMountedMode(); +} +bool UVirtualRealityUtilities::IsRoomMountedMode() +{ + return IDisplayCluster::Get().GetOperationMode() == EDisplayClusterOperationMode::Cluster; +} +bool UVirtualRealityUtilities::IsHeadMountedMode() +{ + return GEngine->XRSystem.IsValid() && GEngine->XRSystem->IsHeadTrackingAllowed(); +} + +FString UVirtualRealityUtilities::GetNodeName() +{ + return IsRoomMountedMode() ? IDisplayCluster::Get().GetClusterMgr()->GetNodeId() : FString(TEXT("Localhost")); +} +float UVirtualRealityUtilities::GetEyeDistance() +{ + return IDisplayCluster::Get().GetConfigMgr()->GetConfigStereo().EyeDist; +} + +EEyeType UVirtualRealityUtilities::GetNodeEyeType() +{ + FDisplayClusterConfigClusterNode CurrentNodeConfig; + IDisplayCluster::Get().GetConfigMgr()->GetClusterNode(GetNodeName(), CurrentNodeConfig); + + FString s = CurrentNodeConfig.ToString(); + + if (s.Contains("mono_eye")) + { + TArray<FString> stringArray; + int32 count = s.ParseIntoArray(stringArray, TEXT(",")); + for (int x = 0; x < count; x++) + { + if (!stringArray[x].Contains("mono_eye")) continue; + if (stringArray[x].Contains("left")) + { + return EEyeType::ET_STEREO_LEFT; + } + if (stringArray[x].Contains("right")) + { + return EEyeType::ET_STEREO_RIGHT; + } + } + } + else + { + return EEyeType::ET_MONO; + } + return EEyeType::ET_MONO; +} + +UDisplayClusterSceneComponent* UVirtualRealityUtilities::GetClusterComponent(const FString& Name) +{ + return IDisplayCluster::Get().GetGameMgr()->GetNodeById(Name); +} diff --git a/Source/DisplayClusterExtensions/Public/VirtualRealityPawn.h b/Source/DisplayClusterExtensions/Public/VirtualRealityPawn.h index 8267bddb37c216099c4da8cd71e242e605684b7e..d5b3b4c8db035bbd1e0095f25d570de5940d0620 100644 --- a/Source/DisplayClusterExtensions/Public/VirtualRealityPawn.h +++ b/Source/DisplayClusterExtensions/Public/VirtualRealityPawn.h @@ -1,106 +1,119 @@ #pragma once -#include "GameFramework/FloatingPawnMovement.h" -#include "GameFramework/PawnMovementComponent.h" -#include "GameFramework/RotatingMovementComponent.h" #include "CoreMinimal.h" +#include "Cluster/DisplayClusterClusterEvent.h" +#include "Cluster/IDisplayClusterClusterManager.h" #include "DisplayClusterPawn.h" #include "DisplayClusterSceneComponent.h" +#include "GameFramework/FloatingPawnMovement.h" +#include "GameFramework/PawnMovementComponent.h" +#include "GameFramework/RotatingMovementComponent.h" #include "MotionControllerComponent.h" #include "VirtualRealityPawn.generated.h" UENUM(BlueprintType) -enum class EVRNavigationModes : uint8{ - nav_mode_none UMETA(DisplayName = "Navigation Mode None"), - nav_mode_fly UMETA(DisplayName = "Navigation Mode Fly") +enum class EVRNavigationModes : uint8 +{ + nav_mode_none UMETA(DisplayName = "Navigation Mode None"), + nav_mode_fly UMETA(DisplayName = "Navigation Mode Fly") }; + UENUM(BlueprintType) -enum class EEyeType : uint8 { - ET_MONO UMETA(DisplayName = "mono"), - ET_STEREO_RIGHT UMETA(DisplayName = "stero_right"), - ET_STEREO_LEFT UMETA(DisplayName = "stereo_left") +enum class EAttachementType : uint8 +{ + AT_NONE UMETA(DisplayName = "not attached"), + AT_HANDTARGET UMETA(DisplayName = "to the right/left hand target"), + AT_FLYSTICK UMETA(DisplayName = "to the Flystick") }; UCLASS() class DISPLAYCLUSTEREXTENSIONS_API AVirtualRealityPawn : public ADisplayClusterPawn { - GENERATED_UCLASS_BODY() + GENERATED_UCLASS_BODY() public: - UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnForward (float Value ); - UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnRight (float Value ); - UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnTurnRate (float Rate ); - UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnLookUpRate(float Rate ); - UFUNCTION(BlueprintNativeEvent, BlueprintCallable, BlueprintCallable, Category = "Pawn") void OnFire(bool Pressed); - UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnAction(bool Pressed, int32 Index); - - UFUNCTION(BlueprintPure, Category = "Pawn") static bool IsDesktopMode(); - UFUNCTION(BlueprintPure, Category = "Pawn") static bool IsRoomMountedMode(); - UFUNCTION(BlueprintPure, Category = "Pawn") static bool IsHeadMountedMode(); - - UFUNCTION(BlueprintPure, Category = "Pawn") static FString GetNodeName(); - UFUNCTION(BlueprintPure, Category = "Pawn") static float GetEyeDistance(); - - UFUNCTION(BlueprintPure, Category = "Pawn") static EEyeType GetNodeEyeType(); - - UFUNCTION(Category = "Pawn") float GetBaseTurnRate() const; - UFUNCTION(Category = "Pawn") void SetBaseTurnRate(float Value); - UFUNCTION(Category = "Pawn") UFloatingPawnMovement* GetFloatingPawnMovement(); - UFUNCTION(Category = "Pawn") URotatingMovementComponent* GetRotatingMovementComponent(); - - //Bunch of Getter Functions for components to avoid users having to know the names - - UFUNCTION(Category = "Pawn") UDisplayClusterSceneComponent* GetFlystickComponent(); - UFUNCTION(Category = "Pawn") UMotionControllerComponent* GetHmdLeftMotionControllerComponent(); - UFUNCTION(Category = "Pawn") UMotionControllerComponent* GetHmdRightMotionControllerComponent(); + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnForward(float Value); + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnRight(float Value); + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnTurnRate(float Rate); + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnLookUpRate(float Rate); + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, BlueprintCallable, Category = "Pawn") void OnFire(bool Pressed); + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnAction(bool Pressed, int32 Index); + + UFUNCTION(Category = "Pawn") float GetBaseTurnRate() const; + UFUNCTION(Category = "Pawn") void SetBaseTurnRate(float Value); + UFUNCTION(Category = "Pawn") UFloatingPawnMovement* GetFloatingPawnMovement(); + UFUNCTION(Category = "Pawn") URotatingMovementComponent* GetRotatingMovementComponent(); + + //Bunch of Getter Functions for components to avoid users having to know the names + UFUNCTION(Category = "Pawn") UDisplayClusterSceneComponent* GetFlystickComponent(); + UFUNCTION(Category = "Pawn") UDisplayClusterSceneComponent* GetRightHandtargetComponent(); + UFUNCTION(Category = "Pawn") UDisplayClusterSceneComponent* GetLeftHandtargetComponent(); + UFUNCTION(Category = "Pawn") UMotionControllerComponent* GetHmdLeftMotionControllerComponent(); + UFUNCTION(Category = "Pawn") UMotionControllerComponent* GetHmdRightMotionControllerComponent(); + + UFUNCTION(Category = "Pawn") USceneComponent* GetHeadComponent(); + UFUNCTION(Category = "Pawn") USceneComponent* GetLeftHandComponent(); + UFUNCTION(Category = "Pawn") USceneComponent* GetRightHandComponent(); + + UFUNCTION(Category = "Pawn") USceneComponent* GetTrackingOriginComponent(); +private: + UFUNCTION(Category = "Pawn") USceneComponent* GetCaveCenterComponent(); + UFUNCTION(Category = "Pawn") USceneComponent* GetShutterGlassesComponent(); - UFUNCTION(Category = "Pawn") USceneComponent* GetHeadComponent(); - UFUNCTION(Category = "Pawn") USceneComponent* GetLeftHandComponent(); - UFUNCTION(Category = "Pawn") USceneComponent* GetRightHandComponent(); +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn") EVRNavigationModes NavigationMode = EVRNavigationModes::nav_mode_fly; - UFUNCTION(Category = "Pawn") USceneComponent* GetCaveOriginComponent(); - UFUNCTION(Category = "Pawn") USceneComponent* GetCaveCenterComponent(); - UFUNCTION(Category = "Pawn") USceneComponent* GetShutterGlassesComponent(); + //Execute specified console command on all nDisplayCluster Nodes + UFUNCTION(Exec, BlueprintCallable, Category = "DisplayCluster") static void ClusterExecute(const FString& Command); - //Get Compenent of Display Cluster by it's name, which is specified in the nDisplay config - UFUNCTION(BlueprintPure, BlueprintCallable, Category = "Pawn") static UDisplayClusterSceneComponent* GetClusterComponent(const FString& Name); - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn") EVRNavigationModes NavigationMode = EVRNavigationModes::nav_mode_fly; +private: + FOnClusterEventListener ClusterEventListenerDelegate; + UFUNCTION() void HandleClusterEvent(const FDisplayClusterClusterEvent& Event); protected: DECLARE_DELEGATE_OneParam(FFireDelegate, bool); DECLARE_DELEGATE_TwoParams(FActionDelegate, bool, int32); - virtual void BeginPlay () override; - virtual void Tick (float DeltaSeconds ) override; - virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override; - virtual UPawnMovementComponent* GetMovementComponent () const override; - - UPROPERTY(EditAnywhere , BlueprintReadWrite, Category = "Pawn", meta = (AllowPrivateAccess = "true")) float BaseTurnRate = 45.0f ; - UPROPERTY(VisibleAnywhere, BlueprintReadOnly , Category = "Pawn", meta = (AllowPrivateAccess = "true")) UFloatingPawnMovement* Movement = nullptr; - UPROPERTY(VisibleAnywhere, BlueprintReadOnly , Category = "Pawn", meta = (AllowPrivateAccess = "true")) URotatingMovementComponent* RotatingMovement = nullptr; - - // Use only when handling cross-device (PC, HMD, CAVE/ROLV) compatibility manually. CAVE/ROLV flystick. - UPROPERTY(VisibleAnywhere, BlueprintReadOnly , Category = "Pawn", meta = (AllowPrivateAccess = "true")) UDisplayClusterSceneComponent* Flystick = nullptr; - // Use only when handling cross-device (PC, HMD, CAVE/ROLV) compatibility manually. HMD left motion controller. - UPROPERTY(VisibleAnywhere, BlueprintReadOnly , Category = "Pawn", meta = (AllowPrivateAccess = "true")) UMotionControllerComponent* HmdLeftMotionController = nullptr; - // Use only when handling cross-device (PC, HMD, CAVE/ROLV) compatibility manually. HMD right motion controller. - UPROPERTY(VisibleAnywhere, BlueprintReadOnly , Category = "Pawn", meta = (AllowPrivateAccess = "true")) UMotionControllerComponent* HmdRightMotionController = nullptr; - - // PC: Camera, HMD: Camera, CAVE/ROLV: Shutter glasses. - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) USceneComponent* Head = nullptr; - // PC: RootComponent, HMD: HmdLeftMotionController , CAVE/ROLV: Flystick. Useful for line trace (e.g. for holding objects). - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) USceneComponent* LeftHand = nullptr; - // PC: RootComponent, HMD: HmdRightMotionController, CAVE/ROLV: Flystick. Useful for line trace (e.g. for holding objects). - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) USceneComponent* RightHand = nullptr; - - // Holding the Cave Origin Component that is attached to this Pawn - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) USceneComponent* CaveOrigin = nullptr; - // Holding the Cave Center Component that is attached to this Pawn - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) USceneComponent* CaveCenter = nullptr; - // Holding the Shutter Glasses Component that is attached to this Pawn - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) USceneComponent* ShutterGlasses = nullptr; + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + virtual void Tick(float DeltaSeconds) override; + virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override; + virtual UPawnMovementComponent* GetMovementComponent() const override; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn", meta = (AllowPrivateAccess = "true")) float BaseTurnRate = 45.0f; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) UFloatingPawnMovement* Movement = nullptr; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) URotatingMovementComponent* RotatingMovement = nullptr; + + // Use only when handling cross-device (PC, HMD, CAVE/ROLV) compatibility manually. CAVE/ROLV flystick. + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) UDisplayClusterSceneComponent* Flystick = nullptr; + // Use only when handling cross-device (PC, HMD, CAVE/ROLV) compatibility manually. CAVE/ROLV flystick. + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) UDisplayClusterSceneComponent* RightHandTarget = nullptr; + // Use only when handling cross-device (PC, HMD, CAVE/ROLV) compatibility manually. CAVE/ROLV flystick. + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) UDisplayClusterSceneComponent* LeftHandTarget = nullptr; + + // Use only when handling cross-device (PC, HMD, CAVE/ROLV) compatibility manually. HMD left motion controller. + UMotionControllerComponent* HmdLeftMotionController = nullptr; + // Use only when handling cross-device (PC, HMD, CAVE/ROLV) compatibility manually. HMD right motion controller. + UMotionControllerComponent* HmdRightMotionController = nullptr; + + // PC: Camera, HMD: Camera, CAVE/ROLV: Shutter glasses. + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) USceneComponent* Head = nullptr; + // PC: RootComponent, HMD: HmdLeftMotionController , CAVE/ROLV: regarding to AttachRightHandInCAVE. Useful for line trace (e.g. for holding objects). + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) USceneComponent* RightHand = nullptr; + // PC: RootComponent, HMD: HmdRightMotionController, CAVE/ROLV: regarding to AttachLeftHandInCAVE. Useful for line trace (e.g. for holding objects). + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) USceneComponent* LeftHand = nullptr; + + // Holding the Cave/rolv Origin Component that is attached to this Pawn + UPROPERTY() USceneComponent* TrackingOrigin = nullptr; + // Holding the Cave Center Component that is attached to this Pawn, it is needed for the internal transform of nDisplay + UPROPERTY() USceneComponent* CaveCenter = nullptr; + // Holding the Shutter Glasses Component that is attached to this Pawn + UPROPERTY() USceneComponent* ShutterGlasses = nullptr; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn") bool ShowHMDControllers = true; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn") EAttachementType AttachRightHandInCAVE = EAttachementType::AT_FLYSTICK; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn") EAttachementType AttachLeftHandInCAVE = EAttachementType::AT_NONE; private: - void InitComponentReferences(); -}; + void InitRoomMountedComponentReferences(); +}; \ No newline at end of file diff --git a/Source/DisplayClusterExtensions/Public/VirtualRealityUtilities.h b/Source/DisplayClusterExtensions/Public/VirtualRealityUtilities.h new file mode 100644 index 0000000000000000000000000000000000000000..1aef9acc66c039c996c28bb32a1ee830108f2730 --- /dev/null +++ b/Source/DisplayClusterExtensions/Public/VirtualRealityUtilities.h @@ -0,0 +1,33 @@ +#pragma once + +#include "CoreMinimal.h" +#include "DisplayClusterSceneComponent.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "VirtualRealityUtilities.generated.h" + +UENUM(BlueprintType) +enum class EEyeType : uint8 +{ + ET_MONO UMETA(DisplayName = "mono"), + ET_STEREO_RIGHT UMETA(DisplayName = "stero_right"), + ET_STEREO_LEFT UMETA(DisplayName = "stereo_left") +}; + +UCLASS() +class DISPLAYCLUSTEREXTENSIONS_API UVirtualRealityUtilities : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintPure, Category = "DisplayCluster") static bool IsDesktopMode(); + UFUNCTION(BlueprintPure, Category = "DisplayCluster") static bool IsRoomMountedMode(); + UFUNCTION(BlueprintPure, Category = "DisplayCluster") static bool IsHeadMountedMode(); + + UFUNCTION(BlueprintPure, Category = "DisplayCluster") static FString GetNodeName(); + UFUNCTION(BlueprintPure, Category = "DisplayCluster") static float GetEyeDistance(); + + UFUNCTION(BlueprintPure, Category = "DisplayCluster") static EEyeType GetNodeEyeType(); + + //Get Compenent of Display Cluster by it's name, which is specified in the nDisplay config + UFUNCTION(BlueprintPure, BlueprintCallable, Category = "DisplayCluster") static UDisplayClusterSceneComponent* GetClusterComponent(const FString& Name); +};