migrate away from the deprecated FXRMotionControllerData in favor of FXRMotionControllerState and FXRHandTrackingState on UE 5.5+
This commit is contained in:
@@ -998,7 +998,9 @@ FTransform FSGXRTracker::FImpl::GetMeshFingerStartBoneRefTransform(
|
||||
}
|
||||
|
||||
bool FSGXRTracker::GetMotionControllerData(
|
||||
UObject* WorldContextObject, const EControllerHand Hand, FXRMotionControllerData& OutMotionControllerData)
|
||||
UObject* WorldContextObject,
|
||||
const EControllerHand Hand,
|
||||
FXRMotionControllerData& OutMotionControllerData)
|
||||
{
|
||||
OutMotionControllerData.DeviceName = NAME_None;
|
||||
OutMotionControllerData.ApplicationInstanceID = FApp::GetInstanceId();
|
||||
@@ -1163,16 +1165,14 @@ bool FSGXRTracker::GetMotionControllerData(
|
||||
{
|
||||
OutMotionControllerData.DeviceVisualType = EXRVisualType::Hand;
|
||||
|
||||
/// TODO
|
||||
// This is a just a temporary workaround to silence a UE 5.5 deprecation warning.
|
||||
// Should be refactored with a proper implementation when migrating away from the deprecated
|
||||
// `FXRMotionControllerData` in favor of newly introduced
|
||||
// `FXRMotionControllerState` and `FXRHandTrackingState` structs.
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
|
||||
bool bTracked = false;
|
||||
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
|
||||
|
||||
OutMotionControllerData.bValid = HandTracker->GetAllKeypointStates(
|
||||
Hand, OutMotionControllerData.HandKeyPositions, OutMotionControllerData.HandKeyRotations,
|
||||
Hand,
|
||||
OutMotionControllerData.HandKeyPositions,
|
||||
OutMotionControllerData.HandKeyRotations,
|
||||
OutMotionControllerData.HandKeyRadii
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
|
||||
, bTracked
|
||||
@@ -1180,10 +1180,25 @@ bool FSGXRTracker::GetMotionControllerData(
|
||||
);
|
||||
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
|
||||
if (!bTracked)
|
||||
// Unused!
|
||||
(void) bTracked;
|
||||
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
|
||||
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
|
||||
// TODO
|
||||
// Begin backward compatibility with the deprecated function, remove this block along with the deprecated
|
||||
// GetAllKeypointStates (though it should be time to remove this entire function as well)!
|
||||
if (!OutMotionControllerData.bValid)
|
||||
{
|
||||
return false;
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
OutMotionControllerData.bValid = HandTracker->GetAllKeypointStates(
|
||||
Hand,
|
||||
OutMotionControllerData.HandKeyPositions,
|
||||
OutMotionControllerData.HandKeyRotations,
|
||||
OutMotionControllerData.HandKeyRadii);
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
}
|
||||
// End backward compability.
|
||||
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
|
||||
|
||||
if (!ensureAlwaysMsgf(
|
||||
@@ -1204,13 +1219,293 @@ bool FSGXRTracker::GetMotionControllerData(
|
||||
OutMotionControllerData.TrackingStatus = ETrackingStatus::Tracked;
|
||||
}
|
||||
|
||||
/// TODO
|
||||
// This is reportedly a WMR-specific convenience function for rapid prototyping. Not sure if it's useful for OpenXR.
|
||||
OutMotionControllerData.bIsGrasped = false;
|
||||
|
||||
return OutMotionControllerData.bValid;
|
||||
}
|
||||
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
|
||||
|
||||
bool FSGXRTracker::GetMotionControllerState(
|
||||
UObject* WorldContextObject,
|
||||
const EXRSpaceType XRSpaceType, const EControllerHand Hand, const EXRControllerPoseType XRControllerPoseType,
|
||||
FXRMotionControllerState& OutMotionControllerState)
|
||||
{
|
||||
auto ToMotionSourceName = [](
|
||||
const EControllerHand Hand, const EXRControllerPoseType XRControllerPoseType) -> FLazyName
|
||||
{
|
||||
static FLazyName LeftAim = "LeftAim";
|
||||
static FLazyName LeftGrip = "LeftGrip";
|
||||
static FLazyName LeftPalm = "LeftPalm";
|
||||
static FLazyName RightAim = "RightAim";
|
||||
static FLazyName RightGrip = "RightGrip";
|
||||
static FLazyName RightPalm = "RightPalm";
|
||||
if (Hand == EControllerHand::Left)
|
||||
{
|
||||
switch (XRControllerPoseType)
|
||||
{
|
||||
case EXRControllerPoseType::Aim:
|
||||
return LeftAim;
|
||||
case EXRControllerPoseType::Grip:
|
||||
return LeftGrip;
|
||||
case EXRControllerPoseType::Palm:
|
||||
return LeftPalm;
|
||||
default:
|
||||
check(false);
|
||||
return LeftGrip;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (XRControllerPoseType)
|
||||
{
|
||||
case EXRControllerPoseType::Aim:
|
||||
return RightAim;
|
||||
case EXRControllerPoseType::Grip:
|
||||
return RightGrip;
|
||||
case EXRControllerPoseType::Palm:
|
||||
return RightPalm;
|
||||
default:
|
||||
check(false);
|
||||
return RightGrip;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
OutMotionControllerState.DeviceName = NAME_None;
|
||||
OutMotionControllerState.ApplicationInstanceID = FApp::GetInstanceId();
|
||||
OutMotionControllerState.TrackingStatus = ETrackingStatus::NotTracked;
|
||||
OutMotionControllerState.Hand = Hand;
|
||||
OutMotionControllerState.XRSpaceType = XRSpaceType;
|
||||
OutMotionControllerState.bValid = false;
|
||||
|
||||
if (!IsValid(WorldContextObject))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsValid(WorldContextObject))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IXRTrackingSystem* XRTrackingSystem{GEngine ? GEngine->XRSystem.Get() : nullptr};
|
||||
if (!XRTrackingSystem)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 4
|
||||
IOpenXRHMD* OpenXRHMD{XRTrackingSystem->GetIOpenXRHMD()};
|
||||
#else /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 4 */
|
||||
FOpenXRHMD* OpenXRHMD{static_cast<FOpenXRHMD*>(GEngine->XRSystem.Get())};
|
||||
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 4 */
|
||||
if (!OpenXRHMD)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TArray<int32> Devices;
|
||||
const int32 HandIndex = static_cast<int32>(Hand);
|
||||
const bool bGotDevices =
|
||||
XRTrackingSystem->EnumerateTrackedDevices(Devices, EXRTrackedDeviceType::Controller);
|
||||
if (bGotDevices && Devices.IsValidIndex(HandIndex))
|
||||
{
|
||||
const XrSession Session{OpenXRHMD->GetSession()};
|
||||
if (Session)
|
||||
{
|
||||
XrInteractionProfileState Profile = {XR_TYPE_INTERACTION_PROFILE_STATE};
|
||||
const XrPath TopLevelUserPath{OpenXRHMD->GetTrackedDevicePath(Devices[HandIndex])};
|
||||
const XrResult CurrentInteractionProfile{
|
||||
xrGetCurrentInteractionProfile(Session, TopLevelUserPath, &Profile)
|
||||
};
|
||||
if (XR_SUCCEEDED(CurrentInteractionProfile) && Profile.interactionProfile != XR_NULL_PATH)
|
||||
{
|
||||
OutMotionControllerState.DeviceName = FOpenXRPath(Profile.interactionProfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((Hand == EControllerHand::Left) || (Hand == EControllerHand::Right))
|
||||
{
|
||||
static const FName MotionControllerName("OpenXR");
|
||||
TArray<IMotionController*> MotionControllers{
|
||||
IModularFeatures::Get().GetModularFeatureImplementations<IMotionController>(
|
||||
IMotionController::GetModularFeatureName())
|
||||
};
|
||||
IMotionController* MotionController{nullptr};
|
||||
for (IMotionController* MotionControllerIterator: MotionControllers)
|
||||
{
|
||||
if (!MotionControllerIterator)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const FName DeviceTypeName{MotionControllerIterator->GetMotionControllerDeviceTypeName()};
|
||||
if (DeviceTypeName != MotionControllerName)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
MotionController = MotionControllerIterator;
|
||||
break;
|
||||
}
|
||||
|
||||
if (MotionController)
|
||||
{
|
||||
{
|
||||
// Handle the pose that is actually being requested.
|
||||
|
||||
const FName MotionSource{ToMotionSourceName(Hand, XRControllerPoseType)};
|
||||
const FTransform TrackingToWorld{
|
||||
XRSpaceType == EXRSpaceType::UnrealWorldSpace
|
||||
? XRTrackingSystem->GetTrackingToWorldTransform()
|
||||
: FTransform::Identity
|
||||
};
|
||||
const float WorldToMeters = XRSpaceType == EXRSpaceType::UnrealWorldSpace
|
||||
? XRTrackingSystem->GetWorldToMetersScale()
|
||||
: 100.0f;
|
||||
|
||||
FVector Position{FVector::ZeroVector};
|
||||
FRotator Rotation{FRotator::ZeroRotator};
|
||||
|
||||
bool bGotMotionControllerOrientationAndPosition = MotionController->GetControllerOrientationAndPosition(
|
||||
0, MotionSource, Rotation, Position, WorldToMeters);
|
||||
|
||||
if (bGotMotionControllerOrientationAndPosition)
|
||||
{
|
||||
OutMotionControllerState.ControllerLocation = TrackingToWorld.TransformPosition(Position);
|
||||
OutMotionControllerState.ControllerRotation = TrackingToWorld.TransformRotation(FQuat{Rotation});
|
||||
}
|
||||
|
||||
OutMotionControllerState.bValid |= bGotMotionControllerOrientationAndPosition;
|
||||
OutMotionControllerState.TrackingStatus =
|
||||
MotionController->GetControllerTrackingStatus(0, MotionSource);
|
||||
}
|
||||
|
||||
{
|
||||
// We always provide the grip transform in Unreal space for XRVisualizationFunctionLibrary;
|
||||
// The bValid and TrackingStatus above are also valid for this pose.
|
||||
|
||||
const FName MotionSource = ToMotionSourceName(Hand, EXRControllerPoseType::Grip);
|
||||
const FTransform TrackingToWorld{XRTrackingSystem->GetTrackingToWorldTransform()};
|
||||
const float WorldToMeters = XRTrackingSystem->GetWorldToMetersScale();
|
||||
|
||||
FVector Position = FVector::ZeroVector;
|
||||
FRotator Rotation = FRotator::ZeroRotator;
|
||||
|
||||
bool bGotMotionControllerOrientationAndPosition = MotionController->GetControllerOrientationAndPosition(
|
||||
0, MotionSource, Rotation, Position, WorldToMeters);
|
||||
|
||||
if (bGotMotionControllerOrientationAndPosition)
|
||||
{
|
||||
OutMotionControllerState.GripUnrealSpaceLocation = TrackingToWorld.TransformPosition(Position);
|
||||
OutMotionControllerState.GripUnrealSpaceRotation =
|
||||
TrackingToWorld.TransformRotation(FQuat(Rotation));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OutMotionControllerState.bValid;
|
||||
}
|
||||
|
||||
bool FSGXRTracker::GetHandTrackingState(
|
||||
UObject* WorldContextObject,
|
||||
const EXRSpaceType XRSpaceType, const EControllerHand Hand,
|
||||
FXRHandTrackingState& OutHandTrackingState)
|
||||
{
|
||||
OutHandTrackingState.ApplicationInstanceID = FApp::GetInstanceId();
|
||||
OutHandTrackingState.TrackingStatus = ETrackingStatus::NotTracked;
|
||||
OutHandTrackingState.Hand = Hand;
|
||||
OutHandTrackingState.XRSpaceType = XRSpaceType;
|
||||
OutHandTrackingState.bValid = false;
|
||||
|
||||
if (!IsValid(WorldContextObject))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IXRTrackingSystem* XRTrackingSystem{GEngine ? GEngine->XRSystem.Get() : nullptr};
|
||||
if (!XRTrackingSystem)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 4
|
||||
IOpenXRHMD* OpenXRHMD{XRTrackingSystem->GetIOpenXRHMD()};
|
||||
#else /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 4 */
|
||||
FOpenXRHMD* OpenXRHMD{static_cast<FOpenXRHMD*>(GEngine->XRSystem.Get())};
|
||||
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 4 */
|
||||
if (!OpenXRHMD)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FName HandTrackerName("OpenXRHandTracking");
|
||||
TArray<IHandTracker*> HandTrackers = IModularFeatures::Get().GetModularFeatureImplementations<IHandTracker>(
|
||||
IHandTracker::GetModularFeatureName());
|
||||
IHandTracker* HandTracker = nullptr;
|
||||
for (auto Itr: HandTrackers)
|
||||
{
|
||||
if (Itr->GetHandTrackerDeviceTypeName() == HandTrackerName)
|
||||
{
|
||||
HandTracker = Itr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((Hand == EControllerHand::Left) || (Hand == EControllerHand::Right))
|
||||
{
|
||||
const bool bHandTrackingStateValid = HandTracker && HandTracker->IsHandTrackingStateValid();
|
||||
if (bHandTrackingStateValid)
|
||||
{
|
||||
bool bTracked = false;
|
||||
OutHandTrackingState.bValid = HandTracker->GetAllKeypointStates(
|
||||
Hand,
|
||||
OutHandTrackingState.HandKeyLocations,
|
||||
OutHandTrackingState.HandKeyRotations,
|
||||
OutHandTrackingState.HandKeyRadii,
|
||||
bTracked);
|
||||
|
||||
/// TODO
|
||||
// Begin backward compatibility with the deprecated function, remove this block along with the deprecated
|
||||
// GetAllKeypointStates.
|
||||
if (!OutHandTrackingState.bValid)
|
||||
{
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
OutHandTrackingState.bValid = HandTracker->GetAllKeypointStates(
|
||||
Hand,
|
||||
OutHandTrackingState.HandKeyLocations,
|
||||
OutHandTrackingState.HandKeyRotations,
|
||||
OutHandTrackingState.HandKeyRadii);
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
bTracked = OutHandTrackingState.bValid;
|
||||
// The inability to distinguish this is the reason for the deprecation.
|
||||
}
|
||||
// End backward compability.
|
||||
|
||||
if (!ensureAlwaysMsgf(
|
||||
!OutHandTrackingState.bValid
|
||||
|| (OutHandTrackingState.HandKeyLocations.Num() == EHandKeypointCount
|
||||
&& OutHandTrackingState.HandKeyRotations.Num() == EHandKeypointCount
|
||||
&& OutHandTrackingState.HandKeyRadii.Num() == EHandKeypointCount),
|
||||
TEXT("Corrupted OutHandTrackingState!")))
|
||||
{
|
||||
OutHandTrackingState.bValid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (OutHandTrackingState.bValid)
|
||||
{
|
||||
OutHandTrackingState.TrackingStatus = bTracked ? ETrackingStatus::Tracked : ETrackingStatus::NotTracked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OutHandTrackingState.bValid;
|
||||
}
|
||||
|
||||
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
|
||||
|
||||
FSGXRTracker::FSGXRTracker(const TSharedRef<FGenericApplicationMessageHandler>& InMessageHandler)
|
||||
: Pimpl(TUniquePtr<FImpl, FImplDeleter>(new FImpl{this}, PimplDeleter))
|
||||
{
|
||||
@@ -1480,7 +1775,7 @@ ETrackingStatus FSGXRTracker::GetControllerTrackingStatus(const int32 Controller
|
||||
if (bFallbackToHandTrackingIfNoGloveDetected)
|
||||
{
|
||||
const FSGXRHandState& HandState{bRight ? GetRightHandState() : GetLeftHandState()};
|
||||
return HandState.bReceivedJointPoses ? ETrackingStatus::Tracked : ETrackingStatus::NotTracked;
|
||||
return HandState.bTracked ? ETrackingStatus::Tracked : ETrackingStatus::NotTracked;
|
||||
}
|
||||
|
||||
return ETrackingStatus::NotTracked;
|
||||
@@ -1606,9 +1901,17 @@ bool FSGXRTracker::GetKeypointState(
|
||||
return bGotTransform;
|
||||
}
|
||||
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
|
||||
bool FSGXRTracker::GetAllKeypointStates(
|
||||
const EControllerHand Hand,
|
||||
TArray<FVector>& OutPositions, TArray<FQuat>& OutRotations, TArray<float>& OutRadii,
|
||||
bool& OutIsTracked) const
|
||||
#else /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
|
||||
bool FSGXRTracker::GetAllKeypointStates(
|
||||
const EControllerHand Hand,
|
||||
TArray<FVector>& OutPositions, TArray<FQuat>& OutRotations, TArray<float>& OutRadii) const
|
||||
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5*/
|
||||
|
||||
{
|
||||
if (!IsHandTrackingStateValid())
|
||||
{
|
||||
@@ -1629,11 +1932,17 @@ bool FSGXRTracker::GetAllKeypointStates(
|
||||
Hand == EControllerHand::Left ? GetLeftHandState() : GetRightHandState()
|
||||
};
|
||||
|
||||
if (!HandState.bReceivedJointPoses)
|
||||
if (!HandState.bHasReceivedJointPoses)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
|
||||
OutIsTracked = HandState.bTracked;
|
||||
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5*/
|
||||
|
||||
// If we ever received poses we return the last data we received, even if not currently tracking to avoid poping
|
||||
// back to (0.0f, 0.0f, 0.0f) and the like.
|
||||
OutPositions.Empty(EHandKeypointCount);
|
||||
OutRotations.Empty(EHandKeypointCount);
|
||||
OutRadii.Empty(EHandKeypointCount);
|
||||
@@ -1765,8 +2074,9 @@ bool FSGXRTracker::FImpl::UpdateXRHandTrackingData(
|
||||
|
||||
XR_ENSURE(XRLocateHandJointsEXT(OutHandState.HandTracker, &LocateInfo, &OutHandState.Locations));
|
||||
|
||||
OutHandState.bReceivedJointPoses = OutHandState.Locations.isActive == XR_TRUE;
|
||||
if (!OutHandState.bReceivedJointPoses)
|
||||
OutHandState.bTracked = OutHandState.Locations.isActive == XR_TRUE;
|
||||
OutHandState.bHasReceivedJointPoses |= HandStates->bTracked;
|
||||
if (!OutHandState.bTracked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1893,21 +2203,16 @@ bool FSGXRTracker::FImpl::GetControllerTransform(
|
||||
if (!bTracked && bFallbackToHandTrackingIfNoGloveDetected)
|
||||
{
|
||||
const FSGXRHandState& HandState{bRight ? Owner->GetRightHandState() : Owner->GetLeftHandState()};
|
||||
if (!HandState.bReceivedJointPoses)
|
||||
if (!HandState.bHasReceivedJointPoses)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const EHandKeypoint KeyPoint = KeyPointInfoPtr->Key;
|
||||
const FTransform& ControllerTransform{
|
||||
bRight
|
||||
? GetRightHandState().GetTransform(KeyPoint)
|
||||
: GetLeftHandState().GetTransform(KeyPoint)
|
||||
};
|
||||
|
||||
const FTransform& ControllerTransform{HandStates->GetTransform(KeyPoint)};
|
||||
OutTransform = ControllerTransform;
|
||||
bOutMotionSourceHandTracking = true;
|
||||
bTracked = true;
|
||||
bTracked = HandState.bTracked;
|
||||
}
|
||||
|
||||
return bTracked;
|
||||
@@ -2404,7 +2709,8 @@ bool FSGXRTracker::FImpl::UpdateSGHandState(const bool bRight, FSGXRHandState& O
|
||||
return false;
|
||||
}
|
||||
|
||||
OutHandState.bReceivedJointPoses = true;
|
||||
OutHandState.bHasReceivedJointPoses = true;
|
||||
OutHandState.bTracked = true;
|
||||
|
||||
const TArray<TArray<FVector>> JointLocations{HandPose->GetJointPositions()};
|
||||
const TArray<TArray<FQuat>> JointRotations{HandPose->GetJointRotationsQ()};
|
||||
@@ -2469,4 +2775,4 @@ bool FSGXRTracker::FImpl::UpdateSGHandState(const bool bRight, FSGXRHandState& O
|
||||
void FSGXRTracker::FImplDeleter::operator()(const FImpl* P) const
|
||||
{
|
||||
delete P;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user