A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
OpenXRExpansionFunctionLibrary.h
Go to the documentation of this file.
1// Fill out your copyright notice in the Description page of Project Settings.
2
3#pragma once
4#include "CoreMinimal.h"
5#include "UObject/ObjectMacros.h"
6#include "Kismet/BlueprintFunctionLibrary.h"
7#include "UObject/Object.h"
8#include "Engine/EngineTypes.h"
9#include "HeadMountedDisplayTypes.h"
10#include "OpenXRCore.h"
11#include "OpenXRHMD.h"
13#include "HeadMountedDisplayFunctionLibrary.h"
14
15#include "Misc/FileHelper.h"
16#include "Misc/Paths.h"
17
18#include "OpenXRExpansionFunctionLibrary.generated.h"
19
20
21DECLARE_LOG_CATEGORY_EXTERN(OpenXRExpansionFunctionLibraryLog, Log, All);
22
23// This needs to be updated as the original gets changed, that or hope they make the original blueprint accessible.
24UENUM(Blueprintable)
25enum class EBPOpenXRControllerDeviceType : uint8
26{
31 //DT_CosmosController,
38};
39
40UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent))
41class OPENXREXPANSIONPLUGIN_API UOpenXRExpansionFunctionLibrary : public UBlueprintFunctionLibrary
42{
43 //GENERATED_BODY()
44 GENERATED_BODY()
45
46public:
47 UOpenXRExpansionFunctionLibrary(const FObjectInitializer& ObjectInitializer);
48
50public:
51
52 static FOpenXRHMD* GetOpenXRHMD()
53 {
54 static FName SystemName(TEXT("OpenXR"));
55 if (GEngine->XRSystem.IsValid() && (GEngine->XRSystem->GetSystemName() == SystemName))
56 {
57 return static_cast<FOpenXRHMD*>(GEngine->XRSystem.Get());
58 }
59
60 return nullptr;
61 }
62
63 UFUNCTION(BlueprintCallable, Category = "VRExpansionFunctions|OpenXR", meta = (bIgnoreSelf = "true"))
64 static bool GetOpenXRHandPose(FBPOpenXRActionSkeletalData& HandPoseContainer, UOpenXRHandPoseComponent* HandPoseComponent, bool bGetMockUpPose = false)
65 {
66 FXRMotionControllerData MotionControllerData;
67
68 if (bGetMockUpPose)
69 {
70 GetMockUpControllerData(MotionControllerData, HandPoseContainer);
71 return true;
72 }
74 UHeadMountedDisplayFunctionLibrary::GetMotionControllerData((UObject*)HandPoseComponent, HandPoseContainer.TargetHand == EVRSkeletalHandIndex::EActionHandIndex_Left ? EControllerHand::Left : EControllerHand::Right, MotionControllerData);
75
76 if (MotionControllerData.bValid)
77 {
78 HandPoseContainer.SkeletalTransforms.Empty(MotionControllerData.HandKeyPositions.Num());
79 FTransform ParentTrans = FTransform::Identity;
80
81 if (MotionControllerData.DeviceVisualType == EXRVisualType::Controller)
82 {
83 ParentTrans = FTransform(MotionControllerData.GripRotation, MotionControllerData.GripPosition, FVector(1.f));
84 }
85 else // EXRVisualType::Hand visual type
86 {
87 ParentTrans = FTransform(MotionControllerData.HandKeyRotations[(uint8)EHandKeypoint::Palm], MotionControllerData.HandKeyPositions[(uint8)EHandKeypoint::Palm], FVector(1.f));
88 }
89
90 for (int i = 0; i < MotionControllerData.HandKeyPositions.Num(); i++)
91 {
92 // Convert to component space, we convert then to parent space later when applying it
93 HandPoseContainer.SkeletalTransforms.Add(FTransform(MotionControllerData.HandKeyRotations[i].GetNormalized(), MotionControllerData.HandKeyPositions[i], FVector(1.f)).GetRelativeTransform(ParentTrans));
94 }
95
96 HandPoseContainer.bHasValidData = true;
97 return true;
98 }
99
100 HandPoseContainer.bHasValidData = false;
101 return false;
102 }
103
104 //UFUNCTION(BlueprintCallable, Category = "VRExpansionFunctions|OpenXR", meta = (bIgnoreSelf = "true"))
105 static void ConvertHandTransformsSpaceAndBack(TArray<FTransform>& OutTransforms, const TArray<FTransform>& WorldTransforms)
106 {
107 // Fail if the count is too low
108 if (WorldTransforms.Num() < EHandKeypointCount)
109 return;
110
111 if (OutTransforms.Num() < WorldTransforms.Num())
112 {
113 OutTransforms.Empty(WorldTransforms.Num());
114 OutTransforms.AddUninitialized(WorldTransforms.Num());
115 }
116
117 // Bone/Parent map
118 int32 BoneParents[26] =
119 {
120 // Manually build the parent hierarchy starting at the wrist which has no parent (-1)
121 1, // Palm -> Wrist
122 -1, // Wrist -> None
123 1, // ThumbMetacarpal -> Wrist
124 2, // ThumbProximal -> ThumbMetacarpal
125 3, // ThumbDistal -> ThumbProximal
126 4, // ThumbTip -> ThumbDistal
127
128 1, // IndexMetacarpal -> Wrist
129 6, // IndexProximal -> IndexMetacarpal
130 7, // IndexIntermediate -> IndexProximal
131 8, // IndexDistal -> IndexIntermediate
132 9, // IndexTip -> IndexDistal
133
134 1, // MiddleMetacarpal -> Wrist
135 11, // MiddleProximal -> MiddleMetacarpal
136 12, // MiddleIntermediate -> MiddleProximal
137 13, // MiddleDistal -> MiddleIntermediate
138 14, // MiddleTip -> MiddleDistal
139
140 1, // RingMetacarpal -> Wrist
141 16, // RingProximal -> RingMetacarpal
142 17, // RingIntermediate -> RingProximal
143 18, // RingDistal -> RingIntermediate
144 19, // RingTip -> RingDistal
145
146 1, // LittleMetacarpal -> Wrist
147 21, // LittleProximal -> LittleMetacarpal
148 22, // LittleIntermediate -> LittleProximal
149 23, // LittleDistal -> LittleIntermediate
150 24, // LittleTip -> LittleDistal
151 };
152
153 // Convert transforms to parent space
154 // The hand tracking transforms are in world space.
155 for (int32 Index = 0; Index < EHandKeypointCount; ++Index)
156 {
157 const FTransform& BoneTransform = WorldTransforms[Index];
158 int32 ParentIndex = BoneParents[Index];
159 int32 ParentParent = -1;
160
161 if (ParentIndex > 0)
162 {
163 ParentParent = BoneParents[ParentIndex];
164 }
165
166 if (ParentIndex < 0)
167 {
168 // We are at the root, so use it.
169 OutTransforms[Index] = BoneTransform;
170 }
171 else
172 {
173 // Merging missing metacarpal bone into the transform
174 if (ParentParent == 1) // Wrist
175 {
176 OutTransforms[Index] = BoneTransform.GetRelativeTransform(WorldTransforms[ParentParent]);
177 }
178 else
179 {
180 OutTransforms[Index] = BoneTransform.GetRelativeTransform(WorldTransforms[ParentIndex]);
181 }
182 }
183 }
184
185 // Check on the easy component space conversion first
186 {
187 for (int32 Index = 0; Index < EHandKeypointCount; ++Index)
188 {
189 const FTransform& BoneTransform = WorldTransforms[Index];
190 int32 ParentIndex = BoneParents[Index];
191 int32 ParentParent = -1;
192
193 if (ParentIndex > 0)
194 {
195 ParentParent = BoneParents[ParentIndex];
196 }
197
198 if (ParentIndex > 0)
199 {
200 if (ParentParent == 1)
201 {
202 OutTransforms[Index] = OutTransforms[Index] * OutTransforms[ParentParent];
203 }
204 else
205 {
206 OutTransforms[Index] = OutTransforms[Index] * OutTransforms[ParentIndex];
207 }
208 }
209 }
210 }
211 }
212
213 //UFUNCTION(BlueprintCallable, Category = "VRExpansionFunctions|OpenXR", meta = (bIgnoreSelf = "true"))
214 static void GetMockUpControllerData(FXRMotionControllerData& MotionControllerData, FBPOpenXRActionSkeletalData& SkeletalMappingData, bool bOpenHand = false)
215 {
216
217
218 TArray<FQuat> HandRotationsClosed = {
219 // Closed palm
220 FQuat(0.419283837f,-0.547548413f,-0.704691410f,-0.166739136f),
221 FQuat(-0.494952023f,0.567746222f,0.647768855f,0.114382625f),
222 FQuat(0.105539620f,-0.079821065f,-0.934957743f,0.329157114f),
223 FQuat(0.309810340f,0.005135804f,-0.887668610f,0.340640306f),
224 FQuat(-0.292820454f,0.003018156f,0.892185807f,-0.343877673f),
225 FQuat(-0.292820454f,0.003018156f,0.892185807f,-0.343877673f),
226 FQuat(0.351302803f,-0.693441451f,-0.594165504f,-0.206626847f),
227 FQuat(0.510899961f,-0.668595433f,-0.531049490f,-0.099752367f),
228 FQuat(0.582462251f,-0.656170130f,-0.478819191f,0.030230284f),
229 FQuat(0.631917894f,-0.637212157f,-0.435243726f,0.072160020f),
230 FQuat(0.631917894f,-0.637212157f,-0.435243726f,0.072160020f),
231 FQuat(0.419282734f,-0.547549129f,-0.704691410f,-0.166739583f),
232 FQuat(0.514688492f,-0.678421855f,-0.501057625f,-0.154207960f),
233 FQuat(0.603475809f,-0.696219206f,-0.388458073f,0.014001161f),
234 FQuat(0.665590405f,-0.681470037f,-0.267755210f,0.144555300f),
235 FQuat(0.670854926f,-0.691665173f,-0.240195125f,0.117731705f),
236 FQuat(0.468501151f,-0.566464663f,-0.638139248f,-0.228914157f),
237 FQuat(0.541896224f,-0.702563524f,-0.417507589f,-0.196058303f),
238 FQuat(0.619513929f,-0.728625834f,-0.289327621f,-0.039927930f),
239 FQuat(0.676032484f,-0.712538362f,-0.151063532f,0.111561134f),
240 FQuat(0.676032484f,-0.712538362f,-0.151063532f,0.111561134f),
241 FQuat(0.541268349f,-0.622995615f,-0.511540473f,-0.239230901f),
242 FQuat(0.545463741f,-0.719190478f,-0.361613214f,-0.233387768f),
243 FQuat(0.613924086f,-0.754614115f,-0.223099023f,-0.062293097f),
244 FQuat(0.682628751f,-0.717284977f,-0.112533726f,0.082796305f),
245 FQuat(0.682628751f,-0.717284977f,-0.112533726f,0.082796305f)
246 };
247 TArray<FQuat> HandRotationsOpen = {
248 // Open Hand
249 FQuat(0.167000905f,-0.670308471f,0.304047525f,-0.656011939f),
250 FQuat(-0.129862994f,0.736467659f,-0.315623045f,0.584065497f),
251 FQuat(-0.030090153f,0.121532254f,-0.840178490f,0.527659237f),
252 FQuat(-0.126470163f,-0.262596279f,0.816956878f,-0.497623593f),
253 FQuat(-0.102322638f,-0.249194950f,0.821705163f,-0.502227187f),
254 FQuat(-0.102322638f,-0.249194950f,0.821705163f,-0.502227187f),
255 FQuat(-0.277370781f,0.686735749f,-0.258646101f,0.620130479f),
256 FQuat(0.193366051f,-0.808131576f,0.260262072f,-0.491728455f),
257 FQuat(0.145547777f,-0.854364336f,0.317562312f,-0.384749293f),
258 FQuat(0.107193023f,-0.879853010f,0.321882188f,-0.332806766f),
259 FQuat(0.107193023f,-0.879853010f,0.321882188f,-0.332806766f),
260 FQuat(0.166999936f,-0.670307159f,0.304047883f,-0.656013489f),
261 FQuat(0.206125781f,-0.815250278f,0.203173012f,-0.501596987f),
262 FQuat(0.164493740f,-0.890369833f,0.257293820f,-0.337613612f),
263 FQuat(0.114019498f,-0.937856555f,0.283619940f,-0.164267495f),
264 FQuat(0.107336335f,-0.925720870f,0.321023613f,-0.168710276f),
265 FQuat(0.156629071f,-0.719596088f,0.210793152f,-0.642817795f),
266 FQuat(0.194258988f,-0.858762920f,0.127883837f,-0.456546605f),
267 FQuat(0.166189745f,-0.930981100f,0.161785051f,-0.281922638f),
268 FQuat(0.119936436f,-0.970744252f,0.189072192f,-0.086731322f),
269 FQuat(0.119936436f,-0.970744252f,0.189072192f,-0.086731322f),
270 FQuat(0.160288095f,-0.812664807f,0.100923792f,-0.551087677f),
271 FQuat(0.207311243f,-0.870556056f,0.056644741f,-0.442656904f),
272 FQuat(0.191506147f,-0.944826961f,0.096772499f,-0.247511998f),
273 FQuat(0.116890728f,-0.981477261f,0.138804480f,-0.061412390f),
274 FQuat(0.116890728f,-0.981477261f,0.138804480f,-0.061412390f)
275 };
276
277 MotionControllerData.HandKeyRotations = SkeletalMappingData.TargetHand != EVRSkeletalHandIndex::EActionHandIndex_Left ? HandRotationsOpen : HandRotationsClosed;
278
279 TArray<FVector> HandPositionsClosed = {
280 // Closed palm - Left
281 FVector(-1203.819f,-516.869f,286.028f),
282 FVector(-1201.705f,-515.876f,287.796),
283 FVector(-1204.748f,-519.489f,288.397),
284 FVector(-1207.823f,-522.044f,287.811),
285 FVector(-1209.696f,-524.000f,286.012),
286 FVector(-1210.690f,-525.034f,285.137),
287 FVector(-1204.366f,-517.319f,288.299),
288 FVector(-1209.332f,-519.116f,283.063),
289 FVector(-1211.344f,-521.651f,280.094),
290 FVector(-1212.261f,-523.927f,278.608),
291 FVector(-1212.474f,-524.895f,278.097),
292 FVector(-1203.111f,-516.601f,286.951),
293 FVector(-1207.318f,-518.192f,281.462),
294 FVector(-1209.140f,-520.536f,278.337),
295 FVector(-1210.042f,-523.368f,276.842),
296 FVector(-1210.136f,-524.640f,276.636),
297 FVector(-1202.057f,-516.294f,286.121),
298 FVector(-1205.064f,-517.866f,280.471),
299 FVector(-1206.431f,-520.299f,277.509),
300 FVector(-1207.089f,-522.828f,276.311),
301 FVector(-1207.154f,-523.888f,276.263),
302 FVector(-1200.966f,-516.092f,285.475),
303 FVector(-1202.852f,-518.796f,280.113),
304 FVector(-1203.746f,-520.657f,277.907),
305 FVector(-1204.180f,-522.291f,277.237),
306 FVector(-1204.222f,-523.061f,277.211)
307 };
308
309 // Open Hand
310 TArray<FVector> HandPositionsOpen = {
311 FVector(-1014.001f,-478.278f,212.902f),
312 FVector(-1013.516f,-476.006f,214.688f),
313 FVector(-1016.362f,-479.642f,215.119f),
314 FVector(-1018.145f,-483.254f,214.805f),
315 FVector(-1019.682f,-485.682f,213.284f),
316 FVector(-1020.480f,-486.982f,212.581f),
317 FVector(-1014.360f,-478.927f,215.169f),
318 FVector(-1014.932f,-484.146f,209.902f),
319 FVector(-1016.872f,-486.643f,206.852f),
320 FVector(-1018.771f,-488.058f,205.231f),
321 FVector(-1019.613f,-488.507f,204.655f),
322 FVector(-1013.901f,-477.534f,213.831f),
323 FVector(-1014.494f,-481.954f,208.310f),
324 FVector(-1016.269f,-484.282f,205.146f),
325 FVector(-1018.657f,-485.834f,203.427f),
326 FVector(-1019.846f,-486.231f,203.113f),
327 FVector(-1013.816f,-476.436f,213.006f),
328 FVector(-1014.637f,-479.707f,207.344f),
329 FVector(-1016.703f,-481.540f,204.355f),
330 FVector(-1018.962f,-482.692f,203.000f),
331 FVector(-1019.978f,-482.975f,202.870f),
332 FVector(-1013.845f,-475.325f,212.363f),
333 FVector(-1015.993f,-477.665f,206.928f),
334 FVector(-1017.571f,-478.907f,204.670f),
335 FVector(-1019.033f,-479.652f,203.887f),
336 FVector(-1019.778f,-479.842f,203.819f)
337 };
338
339 MotionControllerData.HandKeyPositions = SkeletalMappingData.TargetHand != EVRSkeletalHandIndex::EActionHandIndex_Left ? HandPositionsOpen : HandPositionsClosed;
340
342 {
343 MotionControllerData.GripPosition = FVector(-1018.305f, -478.019f, 209.872f);
344 MotionControllerData.GripRotation = FQuat(-0.116352126f, 0.039430488f, -0.757644236f, 0.641001403f);
345 }
346 else
347 {
348 MotionControllerData.GripPosition = FVector(-1202.619f, -521.077f, 283.076f);
349 MotionControllerData.GripRotation = FQuat(0.040843058f, 0.116659224f, 0.980030060f, -0.155767411f);
350 }
351
352 MotionControllerData.DeviceName = TEXT("OpenXR");
353
354 SkeletalMappingData.bHasValidData = true;
355 SkeletalMappingData.SkeletalTransforms.Empty(SkeletalMappingData.SkeletalTransforms.Num());
356 FTransform ParentTrans = FTransform(MotionControllerData.GripRotation, MotionControllerData.GripPosition, FVector(1.f));
357 for (int i = 0; i < MotionControllerData.HandKeyPositions.Num(); i++)
358 {
359 SkeletalMappingData.SkeletalTransforms.Add(FTransform(MotionControllerData.HandKeyRotations[i], MotionControllerData.HandKeyPositions[i], FVector(1.f)).GetRelativeTransform(ParentTrans));
360 }
361 }
362
363 // Get a list of all currently tracked devices and their types, index in the array is their device index
364 // Returns failed if the openXR query failed (no interaction profile yet or openXR is not running)
365 UFUNCTION(BlueprintCallable, Category = "VRExpansionFunctions|OpenXR", meta = (bIgnoreSelf = "true", ExpandEnumAsExecs = "Result"))
366 static void GetXRMotionControllerType(FString& TrackingSystemName, EBPOpenXRControllerDeviceType& DeviceType, EBPXRResultSwitch &Result);
367};
EBPOpenXRControllerDeviceType
UENUM(Blueprintable)
DECLARE_LOG_CATEGORY_EXTERN(OpenXRExpansionFunctionLibraryLog, Log, All)
EBPXRResultSwitch
UENUM()
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent))
static void GetMockUpControllerData(FXRMotionControllerData &MotionControllerData, FBPOpenXRActionSkeletalData &SkeletalMappingData, bool bOpenHand=false)
static bool GetOpenXRHandPose(FBPOpenXRActionSkeletalData &HandPoseContainer, UOpenXRHandPoseComponent *HandPoseComponent, bool bGetMockUpPose=false)
UFUNCTION(BlueprintCallable, Category = "VRExpansionFunctions|OpenXR", meta = (bIgnoreSelf = "true"))
static void ConvertHandTransformsSpaceAndBack(TArray< FTransform > &OutTransforms, const TArray< FTransform > &WorldTransforms)
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent))
USTRUCT(BlueprintType, Category = "VRExpansionFunctions|OpenXR|HandSkeleton")
TArray< FTransform > SkeletalTransforms
UPROPERTY(BlueprintReadOnly, NotReplicated, Transient, Category = Default)
EVRSkeletalHandIndex TargetHand
UPROPERTY(EditAnywhere, NotReplicated, BlueprintReadWrite, Category = Default)
bool bHasValidData
UPROPERTY(NotReplicated, BlueprintReadOnly, Category = Default)