// Copyright PICO Technology Co., Ltd. All rights reserved. // This plugin incorporates portions of the UnrealĀ® Engine. UnrealĀ® is a trademark or registered trademark of Epic Games, Inc. in the United States of America and elsewhere. // Copyright Epic Games, Inc. All Rights Reserved. #include "PXR_MotionTracking.h" #include "PXR_MotionTrackingModule.h" #include "PXR_HMDPrivate.h" #include "PXR_HMD.h" #include "PXR_InputFunctionLibrary.h" #include "PXR_PluginWrapper.h" #include "Logging/MessageLog.h" #include "PXR_MotionTrackingUtility.h" #include "PXR_Utils.h" #include "PXR_Log.h" #include "Async/Async.h" #define LOCTEXT_NAMESPACE "PICOXRMotionTracking" bool PICOXRMotionTracking::GetFaceTrackingSupported(bool& Supported, TArray& SupportedModes) { bool bResult = false; bool supported = false; int modesCount = 0; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetFaceTrackingSupported(&supported, &modesCount, nullptr)); Supported = supported; if (modesCount > 0) { SupportedModes.Reset(modesCount); PxrFaceTrackingMode* modes = new PxrFaceTrackingMode[5]; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetFaceTrackingSupported(&supported, &modesCount, modes)); for (int i = 0; i < modesCount; i++) { SupportedModes.Emplace(EPXRFaceTrackingMode(modes[i])); } delete[] modes; } return bResult; } bool PICOXRMotionTracking::GetFaceTrackingState(bool& IsTracking, FPXRFaceTrackingState& TrackingState) { bool bResult = false; bool isTracking = false; PxrFaceTrackingState state; state.apiVersion = PXR_FACE_TRACKING_API_VERSION; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetFaceTrackingState(&isTracking, &state)); IsTracking = isTracking; TrackingState.CurrentTrackingMode = EPXRFaceTrackingMode(state.currentTrackingMode); TrackingState.TrackingStateCode = EPXRTrackingStateCode(state.code); return bResult; } bool PICOXRMotionTracking::StartFaceTracking(const FPXRFaceTrackingStartInfo& StartInfo) { bool bResult = false; PxrFaceTrackingStartInfo info; info.apiVersion = PXR_FACE_TRACKING_API_VERSION; info.mode = PxrFaceTrackingMode(StartInfo.StartMode); bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().StartFaceTracking(&info)); return bResult; } bool PICOXRMotionTracking::StopFaceTracking(const FPXRFaceTrackingStopInfo& StopInfo) { bool bResult = false; PxrFaceTrackingStopInfo info; info.apiVersion = PXR_FACE_TRACKING_API_VERSION; info.pause = StopInfo.Pause; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().StopFaceTracking(&info)); return bResult; } bool PICOXRMotionTracking::GetFaceTrackingData(const FPXRFaceTrackingDataGetInfo& GetInfo, FPXRFaceTrackingData& OutFaceTrackingData) { bool bResult = false; PxrFaceTrackingDataGetInfo getInfo; getInfo.apiVersion = PXR_FACE_TRACKING_API_VERSION; getInfo.displayTime = GetInfo.DisplayTime; getInfo.flags = PXR_FACE_DEFAULT; PxrFaceTrackingData data; data.apiVersion = PXR_FACE_TRACKING_API_VERSION; data.blendShapeWeight = OutFaceTrackingData.BlendShapeWeights.GetData(); bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetFaceTrackingData1(&getInfo, &data)); OutFaceTrackingData.TimeStamp = data.timestamp; OutFaceTrackingData.LaughingProb = data.laughingProb; OutFaceTrackingData.EyeValid = data.eyeValid; OutFaceTrackingData.FaceValid = data.faceValid; return bResult; } bool PICOXRMotionTracking::GetEyeTrackingSupported(bool& Supported, TArray& SupportedModes) { bool bResult = false; bool supported = false; int modesCount = 0; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetEyeTrackingSupported(&supported, &modesCount, nullptr)); Supported = supported; if (modesCount > 0) { SupportedModes.Reset(modesCount); PxrEyeTrackingMode* modes = new PxrEyeTrackingMode[modesCount]; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetEyeTrackingSupported(&supported, &modesCount, modes)); for (int i = 0; i < modesCount; i++) { SupportedModes.Emplace(EPXREyeTrackingMode(modes[i])); } delete[] modes; } return bResult; } bool PICOXRMotionTracking::GetEyeTrackingState(bool& IsTracking, FPXREyeTrackingState& TrackingState) { bool bResult = false; bool isTracking = false; PxrEyeTrackingState state; state.apiVersion = PXR_EYE_TRACKING_API_VERSION; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetEyeTrackingState(&isTracking, &state)); IsTracking = isTracking; TrackingState.CurrentTrackingMode = EPXREyeTrackingMode(state.currentTrackingMode); TrackingState.TrackingStateCode = EPXRTrackingStateCode(state.code); return bResult; } bool PICOXRMotionTracking::StartEyeTracking(const FPXREyeTrackingStartInfo& StartInfo) { bool bResult = false; PxrEyeTrackingStartInfo info; info.apiVersion = PXR_EYE_TRACKING_API_VERSION; info.mode = PxrEyeTrackingMode((int8)StartInfo.StartMode); info.needCalibration = StartInfo.NeedCalibration; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().StartEyeTracking1(&info)); return bResult; } bool PICOXRMotionTracking::StopEyeTracking(const FPXREyeTrackingStopInfo& StopInfo) { bool bResult = false; PxrEyeTrackingStopInfo info; info.apiVersion = PXR_EYE_TRACKING_API_VERSION; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().StopEyeTracking1(&info)); return bResult; } bool PICOXRMotionTracking::GetEyeTrackingData(float WorldToMetersScale, const FPXREyeTrackingDataGetInfo& GetInfo, FPXREyeTrackingData& OutEyeTrackingData) { bool bResult = false; PxrEyeTrackingDataGetInfo getInfo; getInfo.apiVersion = PXR_EYE_TRACKING_API_VERSION; getInfo.displayTime = GetInfo.DisplayTime; getInfo.flags = PXR_EYE_DEFAULT; if (GetInfo.QueryOrientation) getInfo.flags |= PXR_EYE_POSITION; if (GetInfo.QueryPosition) getInfo.flags |= PXR_EYE_ORIENTATION; PxrEyeTrackingData1 data; FMemory::Memzero(&data, sizeof(data)); data.apiVersion = PXR_EYE_TRACKING_API_VERSION; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetEyeTrackingData1(&getInfo, &data)); if (bResult) { for (uint8 i = 0u; i < static_cast(PxrPerEyeUsage::eyeCount); i++) { const auto& EyeData = data.eyeDatas[i]; OutEyeTrackingData.PerEyeDatas[i].EyeType = (EPICOEye)i; OutEyeTrackingData.PerEyeDatas[i].Position = ToFVector(EyeData.pose.position) * WorldToMetersScale; OutEyeTrackingData.PerEyeDatas[i].Orientation = ToFQuat(EyeData.pose.orientation).Rotator(); OutEyeTrackingData.PerEyeDatas[i].bIsPoseValid = EyeData.isPoseValid; OutEyeTrackingData.PerEyeDatas[i].Openness = EyeData.openness; OutEyeTrackingData.PerEyeDatas[i].bIsOpennessValid = EyeData.isOpennessValid; } } return bResult; } bool PICOXRMotionTracking::GetEyeOpenness(float& LeftEyeOpenness, float& RightEyeOpenness) { bool bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetEyeOpenness(&LeftEyeOpenness, &RightEyeOpenness)); return bResult; } bool PICOXRMotionTracking::GetEyePupilInfo(FPXREyePupilInfo& EyePupilInfo) { PxrEyePupilInfo PxrPupilInfo; bool bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetEyePupilInfo(&PxrPupilInfo)); if (bResult) { EyePupilInfo.LeftEyePupilDiameter = PxrPupilInfo.leftEyePupilDiameter; EyePupilInfo.LeftEyePupilPosition.X = PxrPupilInfo.leftEyePupilPosition[0]; EyePupilInfo.LeftEyePupilPosition.Y = PxrPupilInfo.leftEyePupilPosition[1]; EyePupilInfo.RightEyePupilDiameter = PxrPupilInfo.rightEyePupilDiameter; EyePupilInfo.RightEyePupilPosition.X = PxrPupilInfo.rightEyePupilPosition[0]; EyePupilInfo.RightEyePupilPosition.Y = PxrPupilInfo.rightEyePupilPosition[1]; } return bResult; } bool PICOXRMotionTracking::GetPerEyePose(int64& Timestamp, FTransform& LeftEyePose, FTransform& RightEyePose) { int64_t PoseTimestamp = 0; PxrPosef Left, Right; bool bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetPerEyePose(&PoseTimestamp, &Left, &Right)); if (bResult) { Timestamp = static_cast(PoseTimestamp); LeftEyePose.SetLocation(ToFVector(Left.position)); LeftEyePose.SetRotation(ToFQuat(Left.orientation)); RightEyePose.SetLocation(ToFVector(Right.position)); RightEyePose.SetRotation(ToFQuat(Right.orientation)); } return bResult; } bool PICOXRMotionTracking::GetEyeBlink(int64& Timestamp, bool& bLeftBlink, bool& bRightBlink) { int64_t BlinkTimestamp = 0; bool bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetEyeBlink(&BlinkTimestamp, &bLeftBlink, &bRightBlink)); Timestamp = static_cast(BlinkTimestamp); return bResult; } bool PICOXRMotionTracking::WantBodyTrackingService() { bool bResult = false; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().WantBodyTrackingService()); return bResult; } bool PICOXRMotionTracking::GetBodyTrackingSupported(bool& Supported) { bool bResult = false; bool supported = false; int modesCount = 0; PxrBodyTrackingMode modes = PxrBodyTrackingMode::PXR_BTM_DISABLE; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetBodyTrackingSupported(&supported, &modesCount, &modes)); Supported = supported; return bResult; } bool PICOXRMotionTracking::GetBodyTrackingState(bool& IsTracking, FPXRBodyTrackingState& TrackingState) { bool bResult = false; bool isTracking = false; PxrBodyTrackingState state={}; TrackingState=FPXRBodyTrackingState(); state.apiVersion = PXR_BODY_TRACKING_API_VERSION; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetBodyTrackingState(&isTracking, &state)); IsTracking = isTracking; TrackingState.CurrentTrackingMode = static_cast(state.currentTrackingMode); TrackingState.TrackingStateCode = static_cast(state.code); TrackingState.TrackingStatusCode =static_cast(state.StateCode); TrackingState.TrackingErrorCode =static_cast(state.ErrorCode); TrackingState.ConnectedBandCount=state.connectedBandCount; for (int index=0;index(StartInfo.BodyTrackingMode) : StartInfo.OtherMode; info.BoneLength.HeadLen = StartInfo.BoneLength.headLen; info.BoneLength.NeckLen = StartInfo.BoneLength.neckLen; info.BoneLength.TorsoLen = StartInfo.BoneLength.torsoLen; info.BoneLength.HipLen = StartInfo.BoneLength.hipLen; info.BoneLength.UpperLegLen = StartInfo.BoneLength.upperLegLen; info.BoneLength.LowerLegLen = StartInfo.BoneLength.lowerLegLen; info.BoneLength.FootLen = StartInfo.BoneLength.footLen; info.BoneLength.ShoulderLen = StartInfo.BoneLength.shoulderLen; info.BoneLength.UpperArmLen = StartInfo.BoneLength.upperArmLen; info.BoneLength.LowerArmLen = StartInfo.BoneLength.lowerArmLen; info.BoneLength.HandLen = StartInfo.BoneLength.handLen; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().StartBodyTracking(&info)); return bResult; } bool PICOXRMotionTracking::StopBodyTracking(const FPXRBodyTrackingStopInfo& StopInfo) { bool bResult = false; PxrBodyTrackingStopInfo info={}; info.apiVersion = PXR_BODY_TRACKING_API_VERSION; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().StopBodyTracking(&info)); return bResult; } bool PICOXRMotionTracking::GetBodyTrackingData(float WorldToMetersScale, const FPXRBodyTrackingDataGetInfo& GetInfo, FPXRBodyTrackingData& BodyTrackingData) { bool bResult = false; if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { PxrBodyTrackingGetDataInfo getInfo = {}; getInfo.apiVersion = PXR_BODY_TRACKING_API_VERSION; getInfo.displayTime = GetInfo.DisplayTime; uint8 GetDataMask =static_cast(EPXRBodyTrackingGetDataFlags::PXR_BODY_NONE); for (int32 index = 0; index < GetInfo.DataFlags.Num(); index++) { GetDataMask |= static_cast(GetInfo.DataFlags[index]); getInfo.flags =static_cast(GetDataMask); } PXR_LOGV(PxrUnreal, "GetBodyTrackingData flags %d", getInfo.flags); PxrBodyTrackingData bodydata = {}; FMemory::Memzero(&bodydata, sizeof(bodydata)); bodydata.apiVersion = PXR_BODY_TRACKING_API_VERSION; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetBodyTrackingData(&getInfo, &bodydata)); PXR_LOGV(PxrUnreal, "GetBodyTrackingData bResult %d", bResult); if (bResult) { for (int i = 0; i < 24; i++) { FPxrBodyTrackingTransform element = FPxrBodyTrackingTransform(); element.TimeStamp = static_cast(bodydata.roleData[i].localPose.TimeStamp); element.bone = static_cast(i); element.LocalPose.SetLocation(FVector( -static_cast(bodydata.roleData[i].localPose.PosZ) * WorldToMetersScale, static_cast(bodydata.roleData[i].localPose.PosX) * WorldToMetersScale, static_cast(bodydata.roleData[i].localPose.PosY) * WorldToMetersScale)); element.LocalPose.SetRotation(FQuat( -static_cast(bodydata.roleData[i].localPose.RotQz), static_cast(bodydata.roleData[i].localPose.RotQx), static_cast(bodydata.roleData[i].localPose.RotQy), -static_cast(bodydata.roleData[i].localPose.RotQw))); element.GlobalPose.SetLocation(FVector( -static_cast(bodydata.roleData[i].globalPose.PosZ) * WorldToMetersScale, static_cast(bodydata.roleData[i].globalPose.PosX) * WorldToMetersScale, static_cast(bodydata.roleData[i].globalPose.PosY) * WorldToMetersScale)); element.GlobalPose.SetRotation(FQuat( -static_cast(bodydata.roleData[i].globalPose.RotQz), static_cast(bodydata.roleData[i].globalPose.RotQx), static_cast(bodydata.roleData[i].globalPose.RotQy), -static_cast(bodydata.roleData[i].globalPose.RotQw))); element.velo = FVector(-static_cast(bodydata.roleData[i].velo[2]), static_cast(bodydata.roleData[i].velo[0]), static_cast(bodydata.roleData[i].velo[1])); element.acce = FVector(-static_cast(bodydata.roleData[i].acce[2]), static_cast(bodydata.roleData[i].acce[0]), static_cast(bodydata.roleData[i].acce[1])); element.wvelo = FVector(-static_cast(bodydata.roleData[i].wvelo[2]), static_cast(bodydata.roleData[i].wvelo[0]), static_cast(bodydata.roleData[i].wvelo[1])); element.wacce = FVector(-static_cast(bodydata.roleData[i].wacce[2]), static_cast(bodydata.roleData[i].wacce[0]), static_cast(bodydata.roleData[i].wacce[1])); int Action = static_cast(bodydata.roleData[i].bodyAction); if ((Action & PxrBodyActionList::PxrTouchGround) && (Action & PxrBodyActionList::PxrKeepStatic)) { element.bodyAction = EPxrBodyActionList::TouchGroundAndKeepStatic; } else if (Action & PxrBodyActionList::PxrFootDownAction) { element.bodyAction = EPxrBodyActionList::FootDownAction; } else if (Action & PxrBodyActionList::PxrTouchGround) { element.bodyAction = EPxrBodyActionList::TouchGround; } else if (Action & PxrBodyActionList::PxrKeepStatic) { element.bodyAction = EPxrBodyActionList::KeepStatic; } else if (Action & PxrBodyActionList::PxrTouchGroundToe) { element.bodyAction = EPxrBodyActionList::TouchGroundToe; } else { element.bodyAction = EPxrBodyActionList::NoneAction; } BodyTrackingData.RoleDatas[i] = element; PXR_LOGV(PxrUnreal, "GetBodyTrackingData LocalPose index:%d:Location %s,Rotation %s", i, *BodyTrackingData.RoleDatas[i].LocalPose.GetLocation().ToString(), *BodyTrackingData.RoleDatas[i].LocalPose.GetRotation().ToString()); PXR_LOGV(PxrUnreal, "GetBodyTrackingData GlobalPose index:%d:Location %s,Rotation %s", i, *BodyTrackingData.RoleDatas[i].GlobalPose.GetLocation().ToString(), *BodyTrackingData.RoleDatas[i].GlobalPose.GetRotation().ToString()); } } } return bResult; } bool PICOXRMotionTracking::StartMotionTrackerCalibApp(FString CalibFlagString, int CalibMode) { bool bResult = false; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().StartBodyTrackingCalibApp(TCHAR_TO_ANSI(*CalibFlagString),CalibMode)); return bResult; } FString PICOXRMotionTracking::GetAndroidPackageName() { FString result = FString(""); #if PLATFORM_ANDROID if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) { static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "GetAndroidPackageName", "()Ljava/lang/String;", false); jstring JavaString = (jstring)FJavaWrapper::CallObjectMethod(Env, FJavaWrapper::GameActivityThis, Method); if (JavaString != NULL) { const char* JavaChars = Env->GetStringUTFChars(JavaString, 0); result = FString(UTF8_TO_TCHAR(JavaChars)); Env->ReleaseStringUTFChars(JavaString, JavaChars); Env->DeleteLocalRef(JavaString); } } #endif return result; } bool PICOXRMotionTracking::GetMotionTrackerConnectState(FPXRMotionConnectState& connectState) { bool bResult = false; PxrMotionConnectState MotionConnectStat = {}; connectState=FPXRMotionConnectState(); bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetMotionTrackerConnectState(&MotionConnectStat)); connectState.TrackerSum=MotionConnectStat.trackerSum; for (int index=0;index(MotionTrackerType); return bResult; } bool PICOXRMotionTracking::GetMotionTrackerMode(EPXRMotionTrackerMode& trackerMode) { bool bResult = false; PxrMotionTrackerMode MotionTrackerMode = {}; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetMotionTrackerMode(&MotionTrackerMode)); trackerMode=static_cast(MotionTrackerMode); return bResult; } bool PICOXRMotionTracking::GetMotionTrackerLocations(float WorldToMetersScale, const FString& trackerSN, FPXRMotionTrackerLocations& locations,EPXRMotionTrackerConfidence& Confidence) { bool bResult = false; double dPredictTime = 0; if (FPICOXRHMDModule::GetPluginWrapper().GetPredictedDisplayTime(&dPredictTime)) { return bResult; } PxrMotionTrackerLocations MotionTrackerLocations = {}; int32 ConfidenceInt = 0; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetMotionTrackerLocationsWithConfidence(dPredictTime,TCHAR_TO_ANSI(*trackerSN),&MotionTrackerLocations,&ConfidenceInt)); if (bResult) { Confidence=static_cast(ConfidenceInt); locations.TrackerSN = FString(UTF8_TO_TCHAR(MotionTrackerLocations.trackerSN)); locations.LocalPose.Pose.SetLocation(FVector( -static_cast(MotionTrackerLocations.localPose.pose.position.z) * WorldToMetersScale, static_cast(MotionTrackerLocations.localPose.pose.position.x) * WorldToMetersScale, static_cast(MotionTrackerLocations.localPose.pose.position.y) * WorldToMetersScale)); locations.LocalPose.Pose.SetRotation(FQuat( -static_cast(MotionTrackerLocations.localPose.pose.orientation.z), static_cast(MotionTrackerLocations.localPose.pose.orientation.x), static_cast(MotionTrackerLocations.localPose.pose.orientation.y), -static_cast(MotionTrackerLocations.localPose.pose.orientation.w))); locations.LocalPose.AngularAcceleration = FVector(-static_cast(MotionTrackerLocations.localPose.angularAcceleration[2]), static_cast(MotionTrackerLocations.localPose.angularAcceleration[0]), static_cast(MotionTrackerLocations.localPose.angularAcceleration[1])); locations.LocalPose.AngularVelocity = FVector(-static_cast(MotionTrackerLocations.localPose.angularVelocity[2]), static_cast(MotionTrackerLocations.localPose.angularVelocity[0]), static_cast(MotionTrackerLocations.localPose.angularVelocity[1])); locations.LocalPose.LinearAcceleration = FVector(-static_cast(MotionTrackerLocations.localPose.linearAcceleration[2]), static_cast(MotionTrackerLocations.localPose.linearAcceleration[0]), static_cast(MotionTrackerLocations.localPose.linearAcceleration[1])); locations.LocalPose.LinearVelocity = FVector(-static_cast(MotionTrackerLocations.localPose.linearVelocity[2]), static_cast(MotionTrackerLocations.localPose.linearVelocity[0]), static_cast(MotionTrackerLocations.localPose.linearVelocity[1])); locations.GlobalPose.Pose.SetLocation(FVector( -static_cast(MotionTrackerLocations.globalPose.pose.position.z) * WorldToMetersScale, static_cast(MotionTrackerLocations.globalPose.pose.position.x) * WorldToMetersScale, static_cast(MotionTrackerLocations.globalPose.pose.position.y) * WorldToMetersScale)); locations.GlobalPose.Pose.SetRotation(FQuat( -static_cast(MotionTrackerLocations.globalPose.pose.orientation.z), static_cast(MotionTrackerLocations.globalPose.pose.orientation.x), static_cast(MotionTrackerLocations.globalPose.pose.orientation.y), -static_cast(MotionTrackerLocations.globalPose.pose.orientation.w))); locations.GlobalPose.AngularAcceleration = FVector(-static_cast(MotionTrackerLocations.globalPose.angularAcceleration[2]), static_cast(MotionTrackerLocations.globalPose.angularAcceleration[0]), static_cast(MotionTrackerLocations.globalPose.angularAcceleration[1])); locations.GlobalPose.AngularVelocity = FVector(-static_cast(MotionTrackerLocations.globalPose.angularVelocity[2]), static_cast(MotionTrackerLocations.globalPose.angularVelocity[0]), static_cast(MotionTrackerLocations.globalPose.angularVelocity[1])); locations.GlobalPose.LinearAcceleration = FVector(-static_cast(MotionTrackerLocations.globalPose.linearAcceleration[2]), static_cast(MotionTrackerLocations.globalPose.linearAcceleration[0]), static_cast(MotionTrackerLocations.globalPose.linearAcceleration[1])); locations.GlobalPose.LinearVelocity = FVector(-static_cast(MotionTrackerLocations.globalPose.linearVelocity[2]), static_cast(MotionTrackerLocations.globalPose.linearVelocity[0]), static_cast(MotionTrackerLocations.globalPose.linearVelocity[1])); } return bResult; } void PICOXRMotionTracking::CheckMotionTrackerModeAndNumber(EPXRMotionTrackerMode trackerMode, int32 TrackerNumber) { TrackerNumber=FMath::Clamp(TrackerNumber,0,3); AsyncTask(ENamedThreads::GameThread, [trackerMode, TrackerNumber]() { FPICOXRHMDModule::GetPluginWrapper().CheckMotionTrackerModeAndNumber(static_cast(trackerMode), TrackerNumber); }); } bool PICOXRMotionTracking::GetExtDevTrackerConnectState(FPXRExtDevTrackerConnectState& connectState) { bool bResult = false; PxrExtDevTrackerConnectState ExtDevTrackerConnectState={}; bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetExtDevTrackerConnectState(&ExtDevTrackerConnectState)); if (bResult) { connectState.ExtNumber = ExtDevTrackerConnectState.extNumber; for (int32 index=0;index(passData.PassData[index]); } bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().SetExtDevTrackerByPassData(&ExtDevTrackerPassData)); return bResult; } bool PICOXRMotionTracking::GetExtDevTrackerByPassData(TArray &PassDatas) { bool bResult = false; int32 length=6; int32 realLength; TArray TempPassDatas; TempPassDatas.SetNum(length); bResult = PXRP_SUCCESS(FPICOXRHMDModule::GetPluginWrapper().GetExtDevTrackerByPassData(TempPassDatas.GetData(),length,&realLength)); if (bResult) { for (int32 index=0;index