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

Merge branch 'feature/motion_controller_livelink_workaround' into 'dev/5.3'

Replace LiveLink UniversalTrackedComponent implementation by MotionControllers

See merge request !30
parents 1e1d5d64 2c2b8243
No related branches found
No related tags found
1 merge request!30Replace LiveLink UniversalTrackedComponent implementation by MotionControllers
Showing
with 316 additions and 441 deletions
No preview for this file type
No preview for this file type
// Fill out your copyright notice in the Description page of Project Settings. // Fill out your copyright notice in the Description page of Project Settings.
#include "Pawn/ContinuousMovementComponent.h" #include "Pawn/ContinuousMovementComponent.h"
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"
...@@ -9,6 +8,7 @@ ...@@ -9,6 +8,7 @@
#include "GameFramework/PlayerController.h" #include "GameFramework/PlayerController.h"
#include "Pawn/VRPawnInputConfig.h" #include "Pawn/VRPawnInputConfig.h"
#include "Utility/VirtualRealityUtilities.h" #include "Utility/VirtualRealityUtilities.h"
#include "MotionControllerComponent.h"
void UContinuousMovementComponent::BeginPlay() void UContinuousMovementComponent::BeginPlay()
{ {
...@@ -71,16 +71,6 @@ void UContinuousMovementComponent::SetupInputActions() ...@@ -71,16 +71,6 @@ void UContinuousMovementComponent::SetupInputActions()
// bind additional functions for desktop rotations // bind additional functions for desktop rotations
if (UVirtualRealityUtilities::IsDesktopMode()) if (UVirtualRealityUtilities::IsDesktopMode())
{ {
APlayerController* PC = Cast<APlayerController>(VRPawn->GetController());
if (PC)
{
PC->bShowMouseCursor = true;
PC->bEnableClickEvents = true;
PC->bEnableMouseOverEvents = true;
} else
{
UE_LOG(LogTemp,Error,TEXT("PC Player Controller is invalid"));
}
EI->BindAction(DesktopRotation, ETriggerEvent::Started, this, &UContinuousMovementComponent::StartDesktopRotation); EI->BindAction(DesktopRotation, ETriggerEvent::Started, this, &UContinuousMovementComponent::StartDesktopRotation);
EI->BindAction(DesktopRotation, ETriggerEvent::Completed, this, &UContinuousMovementComponent::EndDesktopRotation); EI->BindAction(DesktopRotation, ETriggerEvent::Completed, this, &UContinuousMovementComponent::EndDesktopRotation);
EI->BindAction(MoveUp, ETriggerEvent::Triggered,this,&UContinuousMovementComponent::OnBeginUp); EI->BindAction(MoveUp, ETriggerEvent::Triggered,this,&UContinuousMovementComponent::OnBeginUp);
...@@ -102,8 +92,8 @@ void UContinuousMovementComponent::OnBeginMove(const FInputActionValue& Value) ...@@ -102,8 +92,8 @@ void UContinuousMovementComponent::OnBeginMove(const FInputActionValue& Value)
const bool bGazeDirected = UVirtualRealityUtilities::IsDesktopMode() || SteeringMode == EVRSteeringModes::STEER_GAZE_DIRECTED; const bool bGazeDirected = UVirtualRealityUtilities::IsDesktopMode() || SteeringMode == EVRSteeringModes::STEER_GAZE_DIRECTED;
const FVector ForwardDir = bGazeDirected ? VRPawn->Head->GetForwardVector() : MovementHand->GetForwardVector(); const FVector ForwardDir = bGazeDirected ? VRPawn->HeadCameraComponent->GetForwardVector() : MovementHand->GetForwardVector();
const FVector RightDir = bGazeDirected ? VRPawn->Head->GetRightVector() : MovementHand->GetRightVector(); const FVector RightDir = bGazeDirected ? VRPawn->HeadCameraComponent->GetRightVector() : MovementHand->GetRightVector();
if (VRPawn->Controller != nullptr) if (VRPawn->Controller != nullptr)
{ {
...@@ -133,10 +123,6 @@ void UContinuousMovementComponent::OnBeginTurn(const FInputActionValue& Value) ...@@ -133,10 +123,6 @@ void UContinuousMovementComponent::OnBeginTurn(const FInputActionValue& Value)
if (TurnValue.X != 0.f) if (TurnValue.X != 0.f)
{ {
VRPawn->AddControllerYawInput(TurnRateFactor * TurnValue.X); VRPawn->AddControllerYawInput(TurnRateFactor * TurnValue.X);
if (UVirtualRealityUtilities::IsDesktopMode())
{
UpdateRightHandForDesktopInteraction();
}
} }
if (TurnValue.Y != 0.f) if (TurnValue.Y != 0.f)
...@@ -144,7 +130,6 @@ void UContinuousMovementComponent::OnBeginTurn(const FInputActionValue& Value) ...@@ -144,7 +130,6 @@ void UContinuousMovementComponent::OnBeginTurn(const FInputActionValue& Value)
if (UVirtualRealityUtilities::IsDesktopMode() && bApplyDesktopRotation) if (UVirtualRealityUtilities::IsDesktopMode() && bApplyDesktopRotation)
{ {
VRPawn->AddControllerPitchInput(TurnRateFactor * -TurnValue.Y); VRPawn->AddControllerPitchInput(TurnRateFactor * -TurnValue.Y);
SetCameraOffset();
} }
} }
} }
...@@ -162,28 +147,6 @@ void UContinuousMovementComponent::OnBeginSnapTurn(const FInputActionValue& Valu ...@@ -162,28 +147,6 @@ void UContinuousMovementComponent::OnBeginSnapTurn(const FInputActionValue& Valu
} }
} }
void UContinuousMovementComponent::SetCameraOffset() const
{
// this also incorporates the BaseEyeHeight, if set as static offset,
// rotations are still around the center of the pawn (on the floor), so pitch rotations look weird
FVector Location;
FRotator Rotation;
VRPawn->GetActorEyesViewPoint(Location, Rotation);
VRPawn->CameraComponent->SetWorldLocationAndRotation(Location, Rotation);
}
void UContinuousMovementComponent::UpdateRightHandForDesktopInteraction()
{
APlayerController* PC = Cast<APlayerController>(VRPawn->GetController());
if (PC)
{
FVector MouseLocation, MouseDirection;
PC->DeprojectMousePositionToWorld(MouseLocation, MouseDirection);
FRotator HandOrientation = MouseDirection.ToOrientationRotator();
VRPawn->RightHand->SetWorldRotation(HandOrientation);
}
}
void UContinuousMovementComponent::OnBeginUp(const FInputActionValue& Value) void UContinuousMovementComponent::OnBeginUp(const FInputActionValue& Value)
{ {
const float MoveValue = Value.Get<FVector2D>().X; const float MoveValue = Value.Get<FVector2D>().X;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "NiagaraDataInterfaceArrayFunctionLibrary.h" #include "NiagaraDataInterfaceArrayFunctionLibrary.h"
#include "Utility/VirtualRealityUtilities.h" #include "Utility/VirtualRealityUtilities.h"
#include "MotionControllerComponent.h"
// Sets default values for this component's properties // Sets default values for this component's properties
UTeleportationComponent::UTeleportationComponent() UTeleportationComponent::UTeleportationComponent()
...@@ -273,7 +274,7 @@ void UTeleportationComponent::SetCameraOffset() const ...@@ -273,7 +274,7 @@ void UTeleportationComponent::SetCameraOffset() const
FVector Location; FVector Location;
FRotator Rotation; FRotator Rotation;
VRPawn->GetActorEyesViewPoint(Location, Rotation); VRPawn->GetActorEyesViewPoint(Location, Rotation);
VRPawn->CameraComponent->SetWorldLocationAndRotation(Location, Rotation); VRPawn->HeadCameraComponent->SetWorldLocationAndRotation(Location, Rotation);
} }
void UTeleportationComponent::UpdateRightHandForDesktopInteraction() void UTeleportationComponent::UpdateRightHandForDesktopInteraction()
......
// Fill out your copyright notice in the Description page of Project Settings.
#include "Pawn/UniversalTrackedComponent.h"
#include "Camera/CameraComponent.h"
#include "Utility/VirtualRealityUtilities.h"
#include "Roles/LiveLinkTransformTypes.h"
#include "ILiveLinkClient.h"
DEFINE_LOG_CATEGORY(LogUniversalTrackedComponent);
// Sets default values for this component's properties
UUniversalTrackedComponent::UUniversalTrackedComponent()
{
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.TickGroup = ETickingGroup::TG_PrePhysics;
bAlwaysUseLiveLinkTracking = false;
}
void UUniversalTrackedComponent::SetShowDeviceModel(const bool bShowControllerModel)
{
if (!UVirtualRealityUtilities::IsHeadMountedMode() || TrackedComponent == nullptr) return;
bShowDeviceModelInHMD = bShowControllerModel;
Cast<UMotionControllerComponent>(TrackedComponent)->SetShowDeviceModel(bShowDeviceModelInHMD);
}
void UUniversalTrackedComponent::BeginPlay()
{
Super::BeginPlay();
if (UVirtualRealityUtilities::IsHeadMountedMode())
{
if (ProxyType == ETrackedComponentType::TCT_HEAD)
{
TrackedComponent = GetOwner()->FindComponentByClass<UCameraComponent>();
}
else
{
/* Spawn Motion Controller Components in HMD Mode*/
UMotionControllerComponent* MotionController = Cast<UMotionControllerComponent>(GetOwner()->AddComponentByClass(UMotionControllerComponent::StaticClass(), false, FTransform::Identity, false));
GetOwner()->AddInstanceComponent(MotionController); // makes it show correctly in the hierarchy
// Todo: If bAlwaysUseLiveLinkTracking is true, those should be sourced by LiveLink
switch(ProxyType)
{
case ETrackedComponentType::TCT_TRACKER_1:
MotionController->SetTrackingMotionSource(FName("Special_1"));
break;
case ETrackedComponentType::TCT_TRACKER_2:
MotionController->SetTrackingMotionSource(FName("Special_2"));
break;
case ETrackedComponentType::TCT_RIGHT_HAND:
MotionController->SetTrackingMotionSource(FName("Right"));
break;
case ETrackedComponentType::TCT_LEFT_HAND:
MotionController->SetTrackingMotionSource(FName("Left"));
break;
default: break;
}
MotionController->SetShowDeviceModel(bShowDeviceModelInHMD);
TrackedComponent = MotionController;
}
if (TrackedComponent)
AttachToComponent(Cast<USceneComponent>(TrackedComponent), FAttachmentTransformRules::SnapToTargetIncludingScale);
}
// Check for bAlwaysUseLiveLinkTracking here too in case we want to use LiveLink in Editor/Desktop mode.
else if (UVirtualRealityUtilities::IsDesktopMode() && !bAlwaysUseLiveLinkTracking)
{
switch(ProxyType)
{
case ETrackedComponentType::TCT_RIGHT_HAND:
case ETrackedComponentType::TCT_LEFT_HAND:
case ETrackedComponentType::TCT_HEAD:
TrackedComponent = GetOwner()->FindComponentByClass<UCameraComponent>(); //All are attached to camera
break;
case ETrackedComponentType::TCT_TRACKER_1:
case ETrackedComponentType::TCT_TRACKER_2:
TrackedComponent = GetOwner()->GetRootComponent();
break;
}
if (TrackedComponent) AttachToComponent(Cast<USceneComponent>(TrackedComponent), FAttachmentTransformRules::SnapToTargetIncludingScale);
}
// If we're either in the cave or using LiveLink, set it up here. Might want to differentiate between the two cases later on,
// for now both should be equivalent. Maybe set up some additional stuff automatically like presets etc.
else if (UVirtualRealityUtilities::IsRoomMountedMode() || bAlwaysUseLiveLinkTracking)
{
// Instead of using the clumsy LiveLinkComponentController, we just directly check the LiveLink Data in Tick later on.
// Set up this Component to Tick, and check whether Subject and Role is set.
// TODO: Check for AttachmentType and automatically get the respective Subject/Role. Need to investigate how those are called by DTrack.
TrackedComponent = this;
bUseLiveLinkTracking = true; // override this in case someone forgot to set it.
if (SubjectRepresentation.Subject.IsNone() || SubjectRepresentation.Role == nullptr)
{
UE_LOG(LogUniversalTrackedComponent, Error, TEXT("UUniversalTrackedComponent::BeginPlay(): No LiveLink Subject or Role is set! Tracking will not work"));
}
SetComponentTickEnabled(true);
}
}
void UUniversalTrackedComponent::PostLoad()
{
Super::PostLoad();
// This is required in PostLoad (and theoretically in OnComponentCreated too) because just setting this in
// the constructor or PostInitializeProperties will load the CDO's property values.
// Just calling it in BeginPlay() won't let us see the LiveLink preview in the editor.
bTickInEditor = bAlwaysUseLiveLinkTracking;
PrimaryComponentTick.bStartWithTickEnabled = bAlwaysUseLiveLinkTracking;
}
#if WITH_EDITOR
void UUniversalTrackedComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
// Catch the change to bAlwaysUseLiveLinkTracking, and disable/enable tick respectively for in-editor tracking.
const FName PropertyName(PropertyChangedEvent.GetPropertyName());
if(PropertyName == GET_MEMBER_NAME_CHECKED(UUniversalTrackedComponent, bAlwaysUseLiveLinkTracking))
{
bTickInEditor = bAlwaysUseLiveLinkTracking;
SetComponentTickEnabled(bAlwaysUseLiveLinkTracking);
}
Super::PostEditChangeProperty(PropertyChangedEvent);
}
#endif
void UUniversalTrackedComponent::TickComponent(const float DeltaTime, const ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// Check whether we need to update the component with new LiveLink data. This is either the case if
// nDisplay uses bUseLiveLinkTracking (Play Mode), or if bAlwaysUseLiveLinkTracking is true, then we tick both in Play Mode and Editor.
const bool bEvaluateLiveLink = bUseLiveLinkTracking || bAlwaysUseLiveLinkTracking;
if(!bEvaluateLiveLink || SubjectRepresentation.Subject.IsNone() || SubjectRepresentation.Role == nullptr)
{
return;
}
// Get the LiveLink interface and evaluate the current existing frame data for the given Subject and Role.
ILiveLinkClient& LiveLinkClient = IModularFeatures::Get().GetModularFeature<ILiveLinkClient>(ILiveLinkClient::ModularFeatureName);
FLiveLinkSubjectFrameData SubjectData;
const bool bHasValidData = LiveLinkClient.EvaluateFrame_AnyThread(SubjectRepresentation.Subject, SubjectRepresentation.Role, SubjectData);
if(!bHasValidData)
return;
// Assume we are using a Transform Role to track the components! This is a slightly dangerous assumption, and could be further improved.
const FLiveLinkTransformStaticData* StaticData = SubjectData.StaticData.Cast<FLiveLinkTransformStaticData>();
const FLiveLinkTransformFrameData* FrameData = SubjectData.FrameData.Cast<FLiveLinkTransformFrameData>();
if (StaticData && FrameData)
{
// Finally, apply the transform to this component according to the static data.
ApplyLiveLinkTransform(FrameData->Transform, *StaticData);
}
}
UMotionControllerComponent* UUniversalTrackedComponent::GetMotionControllerComponentByMotionSource(EControllerHand MotionSource) const
{
TArray<UActorComponent*> Components;
GetOwner()->GetComponents(UMotionControllerComponent::StaticClass(),Components);
return Cast<UMotionControllerComponent>(
Components.FindByPredicate([&MotionSource](UActorComponent* Current)
{
switch(MotionSource)
{
case EControllerHand::Right:
return Cast<UMotionControllerComponent>(Current)->MotionSource == FName("Right");
case EControllerHand::Left:
return Cast<UMotionControllerComponent>(Current)->MotionSource == FName("Left");
default: return true;
}
})[0]
);
}
void UUniversalTrackedComponent::ApplyLiveLinkTransform(const FTransform& Transform, const FLiveLinkTransformStaticData& StaticData)
{
if (bUseLocation && StaticData.bIsLocationSupported)
{
if (bWorldTransform)
{
this->SetWorldLocation(Transform.GetLocation(), bSweep, nullptr, bTeleport ? ETeleportType::TeleportPhysics : ETeleportType::ResetPhysics);
}
else
{
this->SetRelativeLocation(Transform.GetLocation(), bSweep, nullptr, bTeleport ? ETeleportType::TeleportPhysics : ETeleportType::ResetPhysics);
}
}
if (bUseRotation && StaticData.bIsRotationSupported)
{
if (bWorldTransform)
{
this->SetWorldRotation(Transform.GetRotation(), bSweep, nullptr, bTeleport ? ETeleportType::TeleportPhysics : ETeleportType::ResetPhysics);
}
else
{
this->SetRelativeRotation(Transform.GetRotation(), bSweep, nullptr, bTeleport ? ETeleportType::TeleportPhysics : ETeleportType::ResetPhysics);
}
}
if (bUseScale && StaticData.bIsScaleSupported)
{
if (bWorldTransform)
{
this->SetWorldScale3D(Transform.GetScale3D());
}
else
{
this->SetRelativeScale3D(Transform.GetScale3D());
}
}
}
...@@ -85,7 +85,7 @@ void UVRPawnMovement::SetHeadComponent(USceneComponent* NewHeadComponent) ...@@ -85,7 +85,7 @@ void UVRPawnMovement::SetHeadComponent(USceneComponent* NewHeadComponent)
CapsuleColliderComponent->SetupAttachment(HeadComponent); CapsuleColliderComponent->SetupAttachment(HeadComponent);
const float HalfHeight = 80.0f; //this is just an initial value to look good in editor const float HalfHeight = 80.0f; //this is just an initial value to look good in editor
CapsuleColliderComponent->SetCapsuleSize(CapsuleRadius, HalfHeight); CapsuleColliderComponent->SetCapsuleSize(CapsuleRadius, HalfHeight);
CapsuleColliderComponent->SetWorldLocation(FVector(0.0f, 0.0f,HalfHeight)); CapsuleColliderComponent->SetWorldLocation(FVector(0.0f, 0.0f,-HalfHeight));
} }
void UVRPawnMovement::SetCapsuleColliderToUserSize() void UVRPawnMovement::SetCapsuleColliderToUserSize()
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
#include "Engine/LocalPlayer.h" #include "Engine/LocalPlayer.h"
#include "GameFramework/PlayerController.h" #include "GameFramework/PlayerController.h"
#include "Pawn/UniversalTrackedComponent.h"
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h" #include "EnhancedInputSubsystems.h"
#include "MotionControllerComponent.h"
#include "Camera/CameraComponent.h" #include "Camera/CameraComponent.h"
#include "Pawn/VRPawnInputConfig.h" #include "Pawn/VRPawnInputConfig.h"
#include "Pawn/VRPawnMovement.h" #include "Pawn/VRPawnMovement.h"
...@@ -23,46 +23,55 @@ AVirtualRealityPawn::AVirtualRealityPawn(const FObjectInitializer& ObjectInitial ...@@ -23,46 +23,55 @@ AVirtualRealityPawn::AVirtualRealityPawn(const FObjectInitializer& ObjectInitial
SetRootComponent(CreateDefaultSubobject<USceneComponent>(TEXT("Origin"))); SetRootComponent(CreateDefaultSubobject<USceneComponent>(TEXT("Origin")));
CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera")); HeadCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
CameraComponent->SetupAttachment(RootComponent); HeadCameraComponent->SetupAttachment(RootComponent);
CameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, BaseEyeHeight)); //so it is rendered correctly in editor HeadCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, BaseEyeHeight)); //so it is rendered correctly in editor
Head = CreateDefaultSubobject<UUniversalTrackedComponent>(TEXT("Head"));
Head->ProxyType = ETrackedComponentType::TCT_HEAD;
Head->SetupAttachment(RootComponent);
CapsuleRotationFix = CreateDefaultSubobject<USceneComponent>(TEXT("CapsuleRotationFix"));
CapsuleRotationFix->SetUsingAbsoluteRotation(true);
CapsuleRotationFix->SetupAttachment(Head);
PawnMovement = CreateDefaultSubobject<UVRPawnMovement>(TEXT("Pawn Movement")); PawnMovement = CreateDefaultSubobject<UVRPawnMovement>(TEXT("Pawn Movement"));
PawnMovement->SetUpdatedComponent(RootComponent); PawnMovement->SetUpdatedComponent(RootComponent);
PawnMovement->SetHeadComponent(CapsuleRotationFix); PawnMovement->SetHeadComponent(HeadCameraComponent);
RightHand = CreateDefaultSubobject<UUniversalTrackedComponent>(TEXT("Right Hand")); RightHand = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("Right Hand MCC"));
RightHand->ProxyType = ETrackedComponentType::TCT_RIGHT_HAND;
RightHand->AttachementType = EAttachementType::AT_FLYSTICK;
RightHand->SetupAttachment(RootComponent); RightHand->SetupAttachment(RootComponent);
LeftHand = CreateDefaultSubobject<UUniversalTrackedComponent>(TEXT("Left Hand")); LeftHand = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("Left Hand MCC"));
LeftHand->ProxyType = ETrackedComponentType::TCT_LEFT_HAND;
LeftHand->AttachementType = EAttachementType::AT_HANDTARGET;
LeftHand->SetupAttachment(RootComponent); LeftHand->SetupAttachment(RootComponent);
BasicVRInteraction = CreateDefaultSubobject<UBasicVRInteractionComponent>(TEXT("Basic VR Interaction")); BasicVRInteraction = CreateDefaultSubobject<UBasicVRInteractionComponent>(TEXT("Basic VR Interaction"));
BasicVRInteraction->Initialize(RightHand); BasicVRInteraction->Initialize(RightHand);
}
void AVirtualRealityPawn::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
if (UVirtualRealityUtilities::IsDesktopMode())
{
SetCameraOffset();
UpdateRightHandForDesktopInteraction();
}
} }
void AVirtualRealityPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) void AVirtualRealityPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{ {
const APlayerController* PlayerController = Cast<APlayerController>(GetController()); APlayerController* PlayerController = Cast<APlayerController>(GetController());
if (!PlayerController) {
UE_LOG(LogTemp, Error, TEXT("PC Player Controller is invalid"));
return;
}
UEnhancedInputLocalPlayerSubsystem* InputSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()); UEnhancedInputLocalPlayerSubsystem* InputSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer());
if(!InputSubsystem) if(!InputSubsystem)
{ {
UE_LOG(Toolkit,Error,TEXT("[VirtualRealiytPawn.cpp] InputSubsystem IS NOT VALID")); UE_LOG(Toolkit,Error,TEXT("[VirtualRealiytPawn.cpp] InputSubsystem IS NOT VALID"));
} }
if(UVirtualRealityUtilities::IsDesktopMode())
{
PlayerController->bShowMouseCursor = true;
PlayerController->bEnableClickEvents = true;
PlayerController->bEnableMouseOverEvents = true;
}
InputSubsystem->ClearAllMappings(); InputSubsystem->ClearAllMappings();
// add Input Mapping context // add Input Mapping context
...@@ -75,7 +84,29 @@ void AVirtualRealityPawn::SetupPlayerInputComponent(UInputComponent* PlayerInput ...@@ -75,7 +84,29 @@ void AVirtualRealityPawn::SetupPlayerInputComponent(UInputComponent* PlayerInput
EI->BindAction(Fire, ETriggerEvent::Completed, this, &AVirtualRealityPawn::OnEndFire); EI->BindAction(Fire, ETriggerEvent::Completed, this, &AVirtualRealityPawn::OnEndFire);
EI->BindAction(ToggleNavigationMode,ETriggerEvent::Started,this,&AVirtualRealityPawn::OnToggleNavigationMode); EI->BindAction(ToggleNavigationMode,ETriggerEvent::Started,this,&AVirtualRealityPawn::OnToggleNavigationMode);
}
void AVirtualRealityPawn::UpdateRightHandForDesktopInteraction()
{
APlayerController* PC = Cast<APlayerController>(GetController());
if (PC)
{
FVector MouseLocation, MouseDirection;
PC->DeprojectMousePositionToWorld(MouseLocation, MouseDirection);
FRotator HandOrientation = MouseDirection.ToOrientationRotator();
RightHand->SetWorldRotation(HandOrientation);
RightHand->SetRelativeLocation(HeadCameraComponent->GetRelativeLocation());
}
}
void AVirtualRealityPawn::SetCameraOffset() const
{
// this also incorporates the BaseEyeHeight, if set as static offset,
// rotations are still around the center of the pawn (on the floor), so pitch rotations look weird
FVector Location;
FRotator Rotation;
GetActorEyesViewPoint(Location, Rotation);
HeadCameraComponent->SetWorldLocationAndRotation(Location, Rotation);
} }
// legacy grabbing // legacy grabbing
......
...@@ -4,12 +4,24 @@ ...@@ -4,12 +4,24 @@
void FRWTHVRToolkitModule::StartupModule () void FRWTHVRToolkitModule::StartupModule ()
{ {
IModularFeatures& ModularFeatures = IModularFeatures::Get();
if (ModularFeatures.IsModularFeatureAvailable(ILiveLinkClient::ModularFeatureName))
{
FLiveLinkClient* LiveLinkClient = static_cast<FLiveLinkClient*>(&IModularFeatures::Get().GetModularFeature<ILiveLinkClient>(
ILiveLinkClient::ModularFeatureName));
LiveLinkMotionController = MakeUnique<FLiveLinkMotionControllerFix>(*LiveLinkClient);
LiveLinkMotionController->RegisterController();
}
ConsoleActivation.Register(); ConsoleActivation.Register();
} }
void FRWTHVRToolkitModule::ShutdownModule() void FRWTHVRToolkitModule::ShutdownModule()
{ {
ConsoleActivation.Unregister(); ConsoleActivation.Unregister();
if (LiveLinkMotionController)
LiveLinkMotionController->UnregisterController();
} }
......
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Features/IModularFeatures.h"
#include "IMotionController.h"
#include "LiveLinkClient.h"
#include "Roles/LiveLinkTransformRole.h"
#include "Roles/LiveLinkTransformTypes.h"
#define LOCTEXT_NAMESPACE "LiveLinkMotionController"
class FLiveLinkMotionControllerFix : public IMotionController
{
// Internal structure for caching enumerated data
struct FLiveLinkMotionControllerEnumeratedSource
{
// Subject key for talking to live link
FLiveLinkSubjectKey SubjectKey;
// MotionSource name for interacting with Motion Controller system
FName MotionSource;
FLiveLinkMotionControllerEnumeratedSource(const FLiveLinkSubjectKey& Key, FName MotionSourceName) : SubjectKey(Key), MotionSource(MotionSourceName) {}
};
// Built array of Live Link Sources to give to Motion Controller system
TArray<FLiveLinkMotionControllerEnumeratedSource> EnumeratedSources;
public:
FLiveLinkMotionControllerFix(FLiveLinkClient& InClient) : Client(InClient)
{
BuildSourceData();
OnSubjectsChangedHandle = Client.OnLiveLinkSubjectsChanged().AddRaw(this, &FLiveLinkMotionControllerFix::OnSubjectsChangedHandler);
WildcardSource = FGuid::NewGuid();
}
~FLiveLinkMotionControllerFix()
{
Client.OnLiveLinkSubjectsChanged().Remove(OnSubjectsChangedHandle);
OnSubjectsChangedHandle.Reset();
}
void RegisterController()
{
IModularFeatures::Get().RegisterModularFeature(GetModularFeatureName(), this);
}
void UnregisterController()
{
IModularFeatures::Get().UnregisterModularFeature(GetModularFeatureName(), this);
}
virtual bool GetControllerOrientationAndPosition(const int32 ControllerIndex, const FName MotionSource, FRotator& OutOrientation, FVector& OutPosition, float) const override
{
FLiveLinkSubjectKey SubjectKey = GetSubjectKeyFromMotionSource(MotionSource);
FLiveLinkSubjectFrameData FrameData;
if (Client.EvaluateFrame_AnyThread(SubjectKey.SubjectName, ULiveLinkTransformRole::StaticClass(), FrameData))
{
if (FLiveLinkTransformFrameData* TransformFrameData = FrameData.FrameData.Cast<FLiveLinkTransformFrameData>())
{
OutPosition = TransformFrameData->Transform.GetLocation();
OutOrientation = TransformFrameData->Transform.GetRotation().Rotator();
return true;
}
}
return false;
}
virtual bool GetControllerOrientationAndPosition(const int32 ControllerIndex, const FName MotionSource, FRotator& OutOrientation, FVector& OutPosition, bool& OutbProvidedLinearVelocity, FVector& OutLinearVelocity, bool& OutbProvidedAngularVelocity, FVector& OutAngularVelocityAsAxisAndLength, bool& OutbProvidedLinearAcceleration, FVector& OutLinearAcceleration, float WorldToMetersScale) const override
{
OutbProvidedLinearVelocity = false;
OutbProvidedAngularVelocity = false;
OutbProvidedLinearAcceleration = false;
return GetControllerOrientationAndPosition(ControllerIndex, MotionSource, OutOrientation, OutPosition, WorldToMetersScale);
}
virtual bool GetControllerOrientationAndPositionForTime(const int32 ControllerIndex, const FName MotionSource, FTimespan Time, bool& OutTimeWasUsed, FRotator& OutOrientation, FVector& OutPosition, bool& OutbProvidedLinearVelocity, FVector& OutLinearVelocity, bool& OutbProvidedAngularVelocity, FVector& OutAngularVelocityAsAxisAndLength, bool& OutbProvidedLinearAcceleration, FVector& OutLinearAcceleration, float WorldToMetersScale) const override
{
OutTimeWasUsed = false;
OutbProvidedLinearVelocity = false;
OutbProvidedAngularVelocity = false;
OutbProvidedLinearAcceleration = false;
return GetControllerOrientationAndPosition(ControllerIndex, MotionSource, OutOrientation, OutPosition, WorldToMetersScale);
}
float GetCustomParameterValue(const FName MotionSource, FName ParameterName, bool& bValueFound) const override
{
FLiveLinkSubjectKey SubjectKey = GetSubjectKeyFromMotionSource(MotionSource);
FLiveLinkSubjectFrameData EvaluatedData;
if (Client.EvaluateFrame_AnyThread(SubjectKey.SubjectName, ULiveLinkBasicRole::StaticClass(), EvaluatedData))
{
if (EvaluatedData.FrameData.GetBaseData())
{
FLiveLinkBaseFrameData& BaseFrameData = *EvaluatedData.FrameData.GetBaseData();
float FoundValue = 0.f;
if (EvaluatedData.StaticData.GetBaseData()->FindPropertyValue(BaseFrameData, ParameterName, FoundValue))
{
bValueFound = true;
return FoundValue;
}
}
}
bValueFound = false;
return 0.f;
}
virtual ETrackingStatus GetControllerTrackingStatus(const int32 ControllerIndex, const FName MotionSource) const override
{
FLiveLinkSubjectKey SubjectKey = GetSubjectKeyFromMotionSource(MotionSource);
FLiveLinkSubjectFrameData EvaluatedData;
if (Client.EvaluateFrame_AnyThread(SubjectKey.SubjectName, ULiveLinkBasicRole::StaticClass(), EvaluatedData))
{
return ETrackingStatus::Tracked;
}
return ETrackingStatus::NotTracked;
}
virtual FName GetMotionControllerDeviceTypeName() const override
{
static FName LiveLinkMotionControllerName(TEXT("LiveLinkMotionController"));
return LiveLinkMotionControllerName;
}
// Builds cached source data for passing to motion controller system
void BuildSourceData()
{
TArray<FLiveLinkSubjectKey> SubjectKeys = Client.GetSubjects(true, true);
TMap<FGuid, TArray<FName>> LiveLinkSubjects;
LiveLinkSubjects.Add(WildcardSource);
for (const FLiveLinkSubjectKey& Subject : SubjectKeys)
{
LiveLinkSubjects.FindOrAdd(Subject.Source).Add(Subject.SubjectName);
LiveLinkSubjects.FindChecked(WildcardSource).Add(Subject.SubjectName);
}
TArray<FGuid> SourceGuids;
LiveLinkSubjects.GenerateKeyArray(SourceGuids);
typedef TPair<FGuid, FText> FHeaderEntry;
TArray<FHeaderEntry> Headers;
Headers.Reserve(SourceGuids.Num());
for (const FGuid& Source : SourceGuids)
{
FText SourceName = (Source == WildcardSource) ? LOCTEXT("LiveLinkAnySource", "Any") : Client.GetSourceType(Source);
Headers.Emplace(Source, SourceName);
}
{
FGuid& CaptureWildcardSource = WildcardSource;
Headers.Sort([CaptureWildcardSource](const FHeaderEntry& A, const FHeaderEntry& B) { return A.Key == CaptureWildcardSource || A.Value.CompareToCaseIgnored(B.Value) <= 0; });
}
//Build EnumeratedSources data
EnumeratedSources.Reset();
EnumeratedSources.Reserve(SubjectKeys.Num());
for (const FHeaderEntry& Header : Headers)
{
TArray<FName> Subjects = LiveLinkSubjects.FindChecked(Header.Key);
Subjects.Sort(FNameLexicalLess());
for (FName Subject : Subjects)
{
FName FullName = *FString::Format(TEXT("{0} ({1})"), { Subject.ToString(), Header.Value.ToString() });
EnumeratedSources.Emplace(FLiveLinkSubjectKey(Header.Key, Subject), FullName);
}
}
}
virtual void EnumerateSources(TArray<FMotionControllerSource>& Sources) const override
{
for (const FLiveLinkMotionControllerEnumeratedSource& Source : EnumeratedSources)
{
FMotionControllerSource SourceDesc(Source.MotionSource);
#if WITH_EDITOR
static const FName LiveLinkCategoryName(TEXT("LiveLink"));
SourceDesc.EditorCategory = LiveLinkCategoryName;
#endif
Sources.Add(SourceDesc);
}
}
virtual bool GetHandJointPosition(const FName MotionSource, int jointIndex, FVector& OutPosition) const override { return false; }
private:
FLiveLinkSubjectKey GetSubjectKeyFromMotionSource(FName MotionSource) const
{
const FLiveLinkMotionControllerEnumeratedSource* EnumeratedSource = EnumeratedSources.FindByPredicate([&](const FLiveLinkMotionControllerEnumeratedSource& Item) { return Item.MotionSource == MotionSource; });
if (EnumeratedSource)
{
return EnumeratedSource->SubjectKey;
}
return FLiveLinkSubjectKey(FGuid(), MotionSource);
}
// Registered with the client and called when client's subjects change
void OnSubjectsChangedHandler() { BuildSourceData(); }
// Reference to the live link client
FLiveLinkClient& Client;
// Handle to delegate registered with client so we can update when subject state changes
FDelegateHandle OnSubjectsChangedHandle;
// Wildcard source, we don't care about the source itself, just the subject name
FGuid WildcardSource;
};
#undef LOCTEXT_NAMESPACE
...@@ -89,10 +89,10 @@ public: ...@@ -89,10 +89,10 @@ public:
private: private:
UPROPERTY() UPROPERTY()
UUniversalTrackedComponent* MovementHand; UMotionControllerComponent* MovementHand;
UPROPERTY() UPROPERTY()
UUniversalTrackedComponent* RotationHand; UMotionControllerComponent* RotationHand;
UPROPERTY() UPROPERTY()
class UInputMappingContext* IMCMovement; class UInputMappingContext* IMCMovement;
...@@ -102,10 +102,4 @@ private: ...@@ -102,10 +102,4 @@ private:
UPROPERTY() UPROPERTY()
AVirtualRealityPawn* VRPawn; AVirtualRealityPawn* VRPawn;
/**
* Fixes camera rotation in desktop mode.
*/
void SetCameraOffset() const;
void UpdateRightHandForDesktopInteraction();
}; };
...@@ -117,10 +117,10 @@ public: ...@@ -117,10 +117,10 @@ public:
private: private:
UPROPERTY() UPROPERTY()
UUniversalTrackedComponent* TeleportationHand; UMotionControllerComponent* TeleportationHand;
UPROPERTY() UPROPERTY()
UUniversalTrackedComponent* RotationHand; UMotionControllerComponent* RotationHand;
UPROPERTY() UPROPERTY()
class UInputMappingContext* IMCMovement; class UInputMappingContext* IMCMovement;
......
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "LiveLinkRole.h"
#include "Components/SceneComponent.h"
#include "MotionControllerComponent.h"
#include "UniversalTrackedComponent.generated.h"
DECLARE_LOG_CATEGORY_EXTERN(LogUniversalTrackedComponent, Log, All);
struct FLiveLinkTransformStaticData;
UENUM(BlueprintType)
enum class ETrackedComponentType : uint8
{
TCT_TRACKER_1 UMETA(DisplayName = "VIVE Tracker 1"),
TCT_TRACKER_2 UMETA(DisplayName = "VIVE Tracker 2"),
TCT_RIGHT_HAND UMETA(DisplayName = "Right Hand"),
TCT_LEFT_HAND UMETA(DisplayName = "Left Hand"),
TCT_HEAD UMETA(DisplayName = "Head")
};
UENUM(BlueprintType)
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"),
AT_CUSTOM_SUBJECT UMETA(DisplayName = "Custom LiveLink Subject|Role")
};
/*
* Acts as an intelligent proxy object, when attached to a Pawn class
* Attaches itself to the specified controller (Camera, MotionController, TrackedDevice) once they are available
* Behaves according to the ETrackedComponentType which has to be set before starting
*/
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class RWTHVRTOOLKIT_API UUniversalTrackedComponent : public USceneComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UUniversalTrackedComponent();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tracking")
ETrackedComponentType ProxyType = ETrackedComponentType::TCT_HEAD;
/** Set whether LiveLink should always be enabled, even in the editor or desktop mode. Overrides bUseLiveLinkTracking.*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tracking", meta = (DisplayName = "Override all tracking with LiveLink"))
bool bAlwaysUseLiveLinkTracking;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tracking|nDisplay")
EAttachementType AttachementType = EAttachementType::AT_NONE;
/** Set whether nDisplay should use LiveLink tracking. Requires a valid Subject Representation!*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tracking|nDisplay")
bool bUseLiveLinkTracking = true;
/** Set the LiveLink Subject Representation to be used by this component. */
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category="Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
FLiveLinkSubjectRepresentation SubjectRepresentation;
/** Set the transform of the component in world space of in its local reference frame. */
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
bool bWorldTransform = false;
/** Whether we should set the owning actor's location with the value coming from live link. */
UPROPERTY(EditAnywhere, Category = "Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
bool bUseLocation = true;
/** Whether we should set the owning actor's rotation with the value coming from live link. */
UPROPERTY(EditAnywhere, Category = "Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
bool bUseRotation = true;
/** Whether we should set the owning actor's scale with the value coming from live link. */
UPROPERTY(EditAnywhere, Category = "Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
bool bUseScale = true;
/**
* Whether we sweep to the destination location, triggering overlaps along the way and stopping short of the target if blocked by something.
* Only the root component is swept and checked for blocking collision, child components move without sweeping. If collision is off, this has no effect.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
bool bSweep = false;
/**
* Whether we teleport the physics state (if physics collision is enabled for this object).
* If true, physics velocity for this object is unchanged (so ragdoll parts are not affected by change in location).
* If false, physics velocity is updated based on the change in position (affecting ragdoll parts).
* If CCD is on and not teleporting, this will affect objects along the entire sweep volume.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
bool bTeleport = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tracking|HMD", BlueprintSetter=SetShowDeviceModel)
bool bShowDeviceModelInHMD = true;
UFUNCTION(BlueprintSetter)
void SetShowDeviceModel(const bool bShowControllerModel);
//~ Begin SceneComponent Interface
virtual void BeginPlay() override;
virtual void PostLoad() override;
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
#if WITH_EDITOR
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif
//~ End SceneComponent Interface
private:
/**
* @brief Helper function that applies the LiveLink data to this component. Taken from the LiveLink Transform Controller.
* @param Transform Transform read from the LiveLink Client.
* @param StaticData Static data from the LiveLink Subject, defines what is and isn't supported.
* @return void
*/
void ApplyLiveLinkTransform(const FTransform& Transform, const FLiveLinkTransformStaticData& StaticData);
USceneComponent* TrackedComponent = nullptr;
UMotionControllerComponent* GetMotionControllerComponentByMotionSource(EControllerHand MotionSource) const;
};
...@@ -4,13 +4,12 @@ ...@@ -4,13 +4,12 @@
#include "BasicVRInteractionComponent.h" #include "BasicVRInteractionComponent.h"
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "UniversalTrackedComponent.h"
#include "Pawn/VRPawnMovement.h" #include "Pawn/VRPawnMovement.h"
#include "VirtualRealityPawn.generated.h" #include "VirtualRealityPawn.generated.h"
class UCameraComponent; class UCameraComponent;
class ULiveLinkComponentController; class ULiveLinkComponentController;
class UMotionControllerComponent;
/** /**
* *
...@@ -22,31 +21,25 @@ class RWTHVRTOOLKIT_API AVirtualRealityPawn : public APawn ...@@ -22,31 +21,25 @@ class RWTHVRTOOLKIT_API AVirtualRealityPawn : public APawn
public: public:
AVirtualRealityPawn(const FObjectInitializer& ObjectInitializer); AVirtualRealityPawn(const FObjectInitializer& ObjectInitializer);
/* Proxy */ virtual void Tick(float DeltaSeconds) override;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Proxy Objects")
UUniversalTrackedComponent* Head;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Proxy Objects") UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|MotionControllers")
UUniversalTrackedComponent* RightHand; UMotionControllerComponent* RightHand;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Proxy Objects") UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|MotionControllers")
UUniversalTrackedComponent* LeftHand; UMotionControllerComponent* LeftHand;
/* Interaction */ /* Interaction */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Interaction") UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Interaction")
UBasicVRInteractionComponent* BasicVRInteraction; UBasicVRInteractionComponent* BasicVRInteraction;
/* Movement */ /* Movement */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn|Movement")
UVRPawnMovement* PawnMovement;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Movement") UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Movement")
USceneComponent* CapsuleRotationFix; UVRPawnMovement* PawnMovement;
/* CameraComponent */ /* CameraComponent */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Camera") UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Camera")
UCameraComponent* CameraComponent; UCameraComponent* HeadCameraComponent;
protected: protected:
...@@ -72,4 +65,10 @@ protected: ...@@ -72,4 +65,10 @@ protected:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pawn|Input") UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pawn|Input")
class UInputAction* ToggleNavigationMode; class UInputAction* ToggleNavigationMode;
/**
* Fixes camera rotation in desktop mode.
*/
void SetCameraOffset() const;
void UpdateRightHandForDesktopInteraction();
}; };
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Fixes/ActivateConsoleInShipping.h" #include "Fixes/ActivateConsoleInShipping.h"
#include "Fixes/LiveLinkMotionControllerFix.h"
class FRWTHVRToolkitModule : public IModuleInterface class FRWTHVRToolkitModule : public IModuleInterface
...@@ -12,4 +13,5 @@ public: ...@@ -12,4 +13,5 @@ public:
private: private:
FActivateConsoleInShipping ConsoleActivation; FActivateConsoleInShipping ConsoleActivation;
TUniquePtr<FLiveLinkMotionControllerFix> LiveLinkMotionController;
}; };
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment