VRTowerDef/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRControllerComponent...

162 lines
5.9 KiB
C++

// Copyright (c) Meta Platforms, Inc. and affiliates.
// A class to render the currently connected controller.
// Similar to how hands are tracked.
#include "OculusXRControllerComponent.h"
#include "OculusXRInput.h"
#include "Components/StaticMeshComponent.h"
#include "OculusXRHandTracking.h"
#include <OculusXRInputModule.h>
UOculusXRControllerComponent::UOculusXRControllerComponent()
: Super(),
// These position and rotation offsets are needed to correctly position the controller
// when using natural or controller based hand positioning.
// Why do these need to be hardcoded and not come from the skeleton etc?
// It seems like the offset comes from somewhere in unreal in the first place,
// not from a bone position, so there's not a place to load the correct orientation from.
PositionOffsets{
{
FVector(0, 0, 0), // Side: None, Controller Mapping: None
FVector(0, 0, 0), // Side: None, Controller Mapping: Natural
FVector(0, 0, 0), // Side: None, Controller Mapping: Controller
},
{
FVector(0, 0, 0), // Side: Left, Controller Mapping: None
FVector(4.278, 9.969, 4.638), // Side: Left, Controller Mapping: Natural
FVector(4.278, 9.969, 4.638), // Side: Left, Controller Mapping: Controller
},
{
FVector(0, 0, 0), // Side: Right, Controller Mapping: None
FVector(-4.104, -9.993, -4.244), // Side: Right, Controller Mapping: Natural
FVector(-4.104, -9.993, -4.244), // Side: Right, Controller Mapping: Controller
},
}
, RotationOffsets{
{
FVector(0, 0, 0), // Side: None, Controller Mapping: None
FVector(0, 0, 0), // Side: None, Controller Mapping: Natural
FVector(0, 0, 0), // Side: None, Controller Mapping: Controller
},
{
FVector(0, 0, 0), // Side: Left, Controller Mapping: None
FVector(90, 166.229, 263.738), // Side: Left, Controller Mapping: Natural
FVector(90, 168.515, 259.149), // Side: Left, Controller Mapping: Controller
},
{
FVector(0, 0, 0), // Side: Right, Controller Mapping: None
FVector(90, 194.995, 83.863), // Side: Right, Controller Mapping: Natural
FVector(90, 191.485, 79.149), // Side: Right, Controller Mapping: Controller
},
}
{
_meshLoadingState = MeshLoadingState::None;
PrimaryComponentTick.bCanEverTick = true;
}
void UOculusXRControllerComponent::BeginPlay()
{
Super::BeginPlay();
}
void UOculusXRControllerComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// If we're in a capsense mode, we need to offset the controller position so that it's correct / consistent with the hand position.
if (_cachedControllerHandType != OculusXRInput::FOculusHandTracking::ControllerDrivenHandType)
{
_cachedControllerHandType = OculusXRInput::FOculusHandTracking::ControllerDrivenHandType;
const FVector positionOffset = PositionOffsets[static_cast<int>(SkeletonType)][static_cast<int>(_cachedControllerHandType)];
const FVector rotationOffset = RotationOffsets[static_cast<int>(SkeletonType)][static_cast<int>(_cachedControllerHandType)];
SetRelativeLocation(positionOffset);
SetRelativeRotation(FQuat::MakeFromEuler(rotationOffset));
}
bool isHandTrackingEnabled = UOculusXRInputFunctionLibrary::IsHandTrackingEnabled();
bool shouldHide = isHandTrackingEnabled && !(RenderWhenUsingControllerDrivenHands && OculusXRInput::FOculusHandTracking::ControllerDrivenHandType == EOculusXRControllerDrivenHandPoseTypes::Controller);
if (shouldHide && !bHiddenInGame)
{
SetHiddenInGame(true, false);
}
if (!shouldHide && bHiddenInGame)
{
SetHiddenInGame(false, false);
}
if (_meshLoadingState == MeshLoadingState::None || _controllerType != GetControllerType())
{
InitializeMesh();
}
}
EOculusXRControllerType UOculusXRControllerComponent::GetControllerType()
{
EControllerHand controllerHand = EControllerHand::AnyHand;
if (SkeletonType == EOculusXRSide::Left)
{
controllerHand = EControllerHand::Left;
}
else if (SkeletonType == EOculusXRSide::Right)
{
controllerHand = EControllerHand::Right;
}
return UOculusXRFunctionLibrary::GetControllerType(controllerHand);
}
void UOculusXRControllerComponent::InitializeMesh()
{
if (_runtimeMesh != nullptr)
{
SetStaticMesh(nullptr);
_streamableManager.Unload(_runtimeMeshPath);
_runtimeMesh = nullptr;
}
auto left_controller_path = TEXT("none");
auto right_controller_path = TEXT("none");
_controllerType = GetControllerType();
switch (_controllerType)
{
case EOculusXRControllerType::MetaQuestTouch:
left_controller_path = TEXT("/Script/Engine.StaticMesh'/OculusXR/Meshes/LeftTouchForQuest2.LeftTouchForQuest2'");
right_controller_path = TEXT("/Script/Engine.StaticMesh'/OculusXR/Meshes/RightTouchForQuest2.RightTouchForQuest2'");
break;
case EOculusXRControllerType::MetaQuestTouchPlus:
// We don't currently have a model for the touch plus controller, default to the touch pro.
case EOculusXRControllerType::MetaQuestTouchPro:
left_controller_path = TEXT("/Script/Engine.StaticMesh'/OculusXR/Meshes/LeftMetaQuestTouchPro.LeftMetaQuestTouchPro'");
right_controller_path = TEXT("/Script/Engine.StaticMesh'/OculusXR/Meshes/RightMetaQuestTouchPro.RightMetaQuestTouchPro'");
break;
case EOculusXRControllerType::None:
case EOculusXRControllerType::Unknown:
default:
return;
}
auto controllerPath = left_controller_path;
if (SkeletonType == EOculusXRSide::Right)
{
controllerPath = right_controller_path;
}
_runtimeMeshPath = FSoftObjectPath(controllerPath);
_loadAssetHandle = _streamableManager.RequestAsyncLoad(
_runtimeMeshPath,
FStreamableDelegate::CreateUObject(this, &UOculusXRControllerComponent::MeshLoaded));
}
void UOculusXRControllerComponent::MeshLoaded()
{
if (_loadAssetHandle.IsValid() && _loadAssetHandle.Get()->HasLoadCompleted())
{
_runtimeMesh = reinterpret_cast<UStaticMesh*>(_loadAssetHandle.Get()->GetLoadedAsset());
_meshLoadingState = MeshLoadingState::Loaded;
SetStaticMesh(_runtimeMesh);
}
}