update the documentation on consuming the FXRMotionControllerData struct
This commit is contained in:
@@ -6,56 +6,56 @@ Taking a closer look at the `FXRMotionControllerData` declaration inside the Unr
|
||||
USTRUCT(BlueprintType)
|
||||
struct FXRMotionControllerData
|
||||
{
|
||||
GENERATED_USTRUCT_BODY();
|
||||
GENERATED_USTRUCT_BODY();
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
bool bValid = false;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FName DeviceName;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FGuid ApplicationInstanceID;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
EXRVisualType DeviceVisualType = EXRVisualType::Controller;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
bool bValid = false;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FName DeviceName;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FGuid ApplicationInstanceID;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
EXRVisualType DeviceVisualType = EXRVisualType::Controller;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
EControllerHand HandIndex = EControllerHand::Left;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
EControllerHand HandIndex = EControllerHand::Left;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
ETrackingStatus TrackingStatus = ETrackingStatus::NotTracked;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
ETrackingStatus TrackingStatus = ETrackingStatus::NotTracked;
|
||||
|
||||
// Vector representing an object being held in the player's hand
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FVector GripPosition = FVector(0.0f);
|
||||
// Quaternion representing an object being held in the player's hand
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FQuat GripRotation = FQuat(EForceInit::ForceInitToZero);
|
||||
// Vector representing an object being held in the player's hand
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FVector GripPosition = FVector(0.0f);
|
||||
// Quaternion representing an object being held in the player's hand
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FQuat GripRotation = FQuat(EForceInit::ForceInitToZero);
|
||||
|
||||
// For handheld controllers, gives a vector for pointing at objects
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FVector AimPosition = FVector(0.0f);
|
||||
// For handheld controllers, gives a quaternion for pointing at objects
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FQuat AimRotation = FQuat(EForceInit::ForceInitToZero);
|
||||
// For handheld controllers, gives a vector for pointing at objects
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FVector AimPosition = FVector(0.0f);
|
||||
// For handheld controllers, gives a quaternion for pointing at objects
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FQuat AimRotation = FQuat(EForceInit::ForceInitToZero);
|
||||
|
||||
// For handheld controllers, gives a vector for representing the hand
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FVector PalmPosition = FVector(0.0f);
|
||||
// For handheld controllers, gives a quaternion for representing the hand
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FQuat PalmRotation = FQuat(EForceInit::ForceInitToZero);
|
||||
// For handheld controllers, gives a vector for representing the hand
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FVector PalmPosition = FVector(0.0f);
|
||||
// For handheld controllers, gives a quaternion for representing the hand
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
FQuat PalmRotation = FQuat(EForceInit::ForceInitToZero);
|
||||
|
||||
// The indices of this array are the values of EHandKeypoint (Palm, Wrist, ThumbMetacarpal, etc).
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
TArray<FVector> HandKeyPositions;
|
||||
// The indices of this array are the values of EHandKeypoint (Palm, Wrist, ThumbMetacarpal, etc).
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
TArray<FQuat> HandKeyRotations;
|
||||
// The indices of this array are the values of EHandKeypoint (Palm, Wrist, ThumbMetacarpal, etc).
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
TArray<float> HandKeyRadii;
|
||||
// The indices of this array are the values of EHandKeypoint (Palm, Wrist, ThumbMetacarpal, etc).
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
TArray<FVector> HandKeyPositions;
|
||||
// The indices of this array are the values of EHandKeypoint (Palm, Wrist, ThumbMetacarpal, etc).
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
TArray<FQuat> HandKeyRotations;
|
||||
// The indices of this array are the values of EHandKeypoint (Palm, Wrist, ThumbMetacarpal, etc).
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
TArray<float> HandKeyRadii;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
bool bIsGrasped = false;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "XR")
|
||||
bool bIsGrasped = false;
|
||||
};
|
||||
```
|
||||
|
||||
@@ -71,68 +71,88 @@ But, fear not, we've got you covered!
|
||||
|
||||
### Structure Members of FXRMotionControllerData
|
||||
|
||||
1. **bValid**
|
||||
- **bValid**
|
||||
- **Description**: A boolean flag indicating whether the data is valid or not.
|
||||
- **Usage**: This is used to check if the motion controller data is correctly initialized and can be used for further processing.
|
||||
|
||||
2. **DeviceName**
|
||||
- **DeviceName**
|
||||
- **Type**: `FName`
|
||||
- **Description**: The name of the device.
|
||||
- **Usage**: Identifies which motion controller device the data is coming from, useful when multiple devices are in use.
|
||||
|
||||
3. **ApplicationInstanceID**
|
||||
- **ApplicationInstanceID**
|
||||
- **Type**: `FString`
|
||||
- **Description**: A unique identifier for the application instance.
|
||||
- **Usage**: Helps in differentiating data from different instances of an application, ensuring the correct instance processes the data.
|
||||
|
||||
4. **TrackingStatus**
|
||||
- **DeviceVisualType**
|
||||
- **Type**: `EXRVisualType`
|
||||
- **Description**: Enum specifying the visual type of the device (e.g., controller, hand).
|
||||
- **Usage**: Used to differentiate between various motion controller devices or hand-tracking representations for rendering and interaction purposes.
|
||||
|
||||
- **HandIndex**
|
||||
- **Type**: `EControllerHand`
|
||||
- **Description**: Enum indicating which hand is being tracked (left or right).
|
||||
- **Usage**: Helps identify whether the motion data pertains to the left or right hand, essential for hand-specific actions or interactions.
|
||||
|
||||
- **TrackingStatus**
|
||||
- **Type**: `EXRTrackingStatus`
|
||||
- **Description**: Enum indicating the tracking status of the motion controller.
|
||||
- **Usage**: Shows whether the controller is being tracked accurately, with possible statuses like `Tracked`, `NotTracked`, etc.
|
||||
|
||||
5. **GripPosition**
|
||||
- **GripPosition**
|
||||
- **Type**: `FVector`
|
||||
- **Description**: The position of the grip in world coordinates.
|
||||
- **Usage**: Provides the 3D coordinates of the controller's grip, essential for positioning the virtual representation of the controller.
|
||||
|
||||
6. **GripRotation**
|
||||
- **GripRotation**
|
||||
- **Type**: `FQuat`
|
||||
- **Description**: The rotation of the grip in world coordinates.
|
||||
- **Usage**: Provides the orientation of the controller's grip, allowing for accurate rotation and alignment in the virtual space.
|
||||
|
||||
7. **AimPosition**
|
||||
- **AimPosition**
|
||||
- **Type**: `FVector`
|
||||
- **Description**: The position of the aim point in world coordinates.
|
||||
- **Usage**: Specifies where the controller is aiming, useful for aiming or pointing actions.
|
||||
|
||||
8. **AimRotation**
|
||||
- **AimRotation**
|
||||
- **Type**: `FQuat`
|
||||
- **Description**: The rotation of the aim point in world coordinates.
|
||||
- **Usage**: Determines the orientation of the aim direction, important for actions like shooting or selecting objects in VR.
|
||||
|
||||
9. **HandKeyPositions**
|
||||
- **PalmPosition**
|
||||
- **Type**: `FVector`
|
||||
- **Description**: The position of the palm in world coordinates.
|
||||
- **Usage**: Provides the 3D location of the palm, important for determining hand gestures or interactions in VR.
|
||||
|
||||
- **PalmRotation**
|
||||
- **Type**: `FQuat`
|
||||
- **Description**: The rotation of the palm in world coordinates.
|
||||
- **Usage**: Defines the orientation of the palm, crucial for hand-based interaction accuracy and realism in VR experiences.
|
||||
|
||||
- **HandKeyPositions**
|
||||
- **Type**: `TArray<FVector>`
|
||||
- **Description**: An array of vectors representing key positions of the hand.
|
||||
- **Usage**: Provides detailed positions of key points on the hand, useful for precise hand tracking and interaction.
|
||||
|
||||
10. **HandKeyRotations**
|
||||
- **HandKeyRotations**
|
||||
- **Type**: `TArray<FQuat>`
|
||||
- **Description**: An array of quaternions representing key rotations of the hand.
|
||||
- **Usage**: Complements the hand key positions with rotational data, ensuring accurate representation of hand movements.
|
||||
|
||||
11. **HandKeyRadii**
|
||||
- **HandKeyRadii**
|
||||
- **Type**: `TArray<float>`
|
||||
- **Description**: An array of floats representing the radii of key points of the hand.
|
||||
- **Usage**: Gives the size of the hand key points, aiding in collision detection and interaction fidelity.
|
||||
|
||||
12. **bIsGrasped**
|
||||
- **bIsGrasped**
|
||||
- **Type**: `bool`
|
||||
- **Description**: A boolean indicating whether the controller is currently grasping an object.
|
||||
- **Usage**: Determines if the user is holding something, affecting interactions and animations.
|
||||
|
||||
### Organization of FXRMotionControllerData
|
||||
|
||||
The structure is organized to encapsulate all relevant data needed for motion controller tracking in a coherent and accessible manner. Boolean flags `bValid` and `bIsGrasped` provide quick checks on the state of the controller data. Identifiers `DeviceName` and `ApplicationInstanceID` ensure the correct association of data. Positional and rotational data `GripPosition`, `GripRotation`, `AimPosition`, and `AimRotation` offer precise tracking of the controller's movement. Arrays `HandKeyPositions`, `HandKeyRotations`, and `HandKeyRadii` allow detailed hand tracking, which is critical for immersive VR experiences. Lastly, the tracking status `TrackingStatus` informs the system of the reliability of the data being processed and whether the motion controller is actively being tracked or it's inactive at the moment.
|
||||
The structure is organized to encapsulate all relevant data needed for hand and motion controller tracking in a coherent and accessible manner. Boolean flags `bValid` and `bIsGrasped` provide quick checks on the state of the controller data. Identifiers `DeviceName` and `ApplicationInstanceID` ensure the correct association of data. Positional and rotational data `GripPosition`, `GripRotation`, `AimPosition`, and `AimRotation` offer precise tracking of the controller's movement. Arrays `HandKeyPositions`, `HandKeyRotations`, and `HandKeyRadii` allow detailed hand tracking, which is critical for immersive VR experiences. Lastly, the tracking status `TrackingStatus` informs the system of the reliability of the data being processed and whether the motion controller is actively being tracked or it's inactive at the moment.
|
||||
|
||||
### Processing the Data for Drawing and Animating a Virtual Hand
|
||||
|
||||
@@ -150,32 +170,32 @@ Unreal Engine also provides an enum called `EHandKeypoint` naming the 26 joints,
|
||||
UENUM(BlueprintType)
|
||||
enum class EHandKeypoint : uint8
|
||||
{
|
||||
Palm,
|
||||
Wrist,
|
||||
ThumbMetacarpal,
|
||||
ThumbProximal,
|
||||
ThumbDistal,
|
||||
ThumbTip,
|
||||
IndexMetacarpal,
|
||||
IndexProximal,
|
||||
IndexIntermediate,
|
||||
IndexDistal,
|
||||
IndexTip,
|
||||
MiddleMetacarpal,
|
||||
MiddleProximal,
|
||||
MiddleIntermediate,
|
||||
MiddleDistal,
|
||||
MiddleTip,
|
||||
RingMetacarpal,
|
||||
RingProximal,
|
||||
RingIntermediate,
|
||||
RingDistal,
|
||||
RingTip,
|
||||
LittleMetacarpal,
|
||||
LittleProximal,
|
||||
LittleIntermediate,
|
||||
LittleDistal,
|
||||
LittleTip
|
||||
Palm,
|
||||
Wrist,
|
||||
ThumbMetacarpal,
|
||||
ThumbProximal,
|
||||
ThumbDistal,
|
||||
ThumbTip,
|
||||
IndexMetacarpal,
|
||||
IndexProximal,
|
||||
IndexIntermediate,
|
||||
IndexDistal,
|
||||
IndexTip,
|
||||
MiddleMetacarpal,
|
||||
MiddleProximal,
|
||||
MiddleIntermediate,
|
||||
MiddleDistal,
|
||||
MiddleTip,
|
||||
RingMetacarpal,
|
||||
RingProximal,
|
||||
RingIntermediate,
|
||||
RingDistal,
|
||||
RingTip,
|
||||
LittleMetacarpal,
|
||||
LittleProximal,
|
||||
LittleIntermediate,
|
||||
LittleDistal,
|
||||
LittleTip
|
||||
};
|
||||
|
||||
const int32 EHandKeypointCount = static_cast<int32>(EHandKeypoint::LittleTip) + 1;
|
||||
@@ -217,7 +237,7 @@ So, getting the any joint's position or rotation is as easy as casting the enum
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure that MotionControllerData.HandKeyPositions has the rotation data
|
||||
// Ensure that MotionControllerData.HandKeyRotations has the rotation data
|
||||
// for 26 joints!
|
||||
if (!ensureAlwaysMsgf(MotionControllerData.HandKeyRotations.Num()
|
||||
== EHandKeypointCount,
|
||||
|
||||
@@ -48,4 +48,4 @@ Before continuing this section, please ensure you've studied the [Consuming FXRM
|
||||
|
||||
13. Now, go back to the `VRTemplateMap` and use the VR Preview button to run the game. If everything's done correctly, you should be able to see the virtual hands inside your VR simulation.
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -47,30 +47,30 @@ using UnrealBuildTool;
|
||||
|
||||
public class VirtualHandCpp : ModuleRules
|
||||
{
|
||||
public VirtualHandCpp(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
|
||||
public VirtualHandCpp(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(new string[]
|
||||
{
|
||||
"InputDevice",
|
||||
"OpenXRHMD",
|
||||
"SenseGloveBuildHacks",
|
||||
"SenseGloveDebug",
|
||||
"SenseGloveSettings",
|
||||
"SenseGloveTracking"
|
||||
});
|
||||
PrivateDependencyModuleNames.AddRange(new string[]
|
||||
{
|
||||
"InputDevice",
|
||||
"OpenXRHMD",
|
||||
"SenseGloveBuildHacks",
|
||||
"SenseGloveDebug",
|
||||
"SenseGloveSettings",
|
||||
"SenseGloveTracking"
|
||||
});
|
||||
|
||||
// Uncomment if you are using Slate UI
|
||||
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
|
||||
|
||||
// Uncomment if you are using online features
|
||||
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
|
||||
// Uncomment if you are using Slate UI
|
||||
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
|
||||
|
||||
// Uncomment if you are using online features
|
||||
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
|
||||
|
||||
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
|
||||
}
|
||||
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -93,32 +93,32 @@ public class VirtualHandCpp : ModuleRules
|
||||
UCLASS()
|
||||
class VIRTUALHANDCPP_API ADebugPawn : public APawn
|
||||
{
|
||||
GENERATED_BODY()
|
||||
GENERATED_BODY()
|
||||
|
||||
private:
|
||||
// The virtual hand drawing settings.
|
||||
UPROPERTY(EditDefaultsOnly, Category="DebugPawn",
|
||||
meta=(AllowPrivateAccess="false"))
|
||||
FSGDebugGizmoSettings HandDrawingSettings;
|
||||
// The virtual hand drawing settings.
|
||||
UPROPERTY(EditDefaultsOnly, Category="DebugPawn",
|
||||
meta=(AllowPrivateAccess="false"))
|
||||
FSGDebugGizmoSettings HandDrawingSettings;
|
||||
|
||||
public:
|
||||
// Sets default values for this pawn's properties
|
||||
ADebugPawn();
|
||||
// Sets default values for this pawn's properties
|
||||
ADebugPawn();
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
public:
|
||||
// Called every frame
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
// Called every frame
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
|
||||
// Called to bind functionality to input
|
||||
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
|
||||
// Called to bind functionality to input
|
||||
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
|
||||
|
||||
private:
|
||||
// The method responsible for drawing a virtual hand.
|
||||
void DrawHand(EControllerHand Hand) const;
|
||||
// The method responsible for drawing a virtual hand.
|
||||
void DrawHand(EControllerHand Hand) const;
|
||||
};
|
||||
```
|
||||
|
||||
@@ -137,116 +137,116 @@ private:
|
||||
// Sets default values
|
||||
ADebugPawn::ADebugPawn()
|
||||
{
|
||||
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
|
||||
// Set the default virtual hand drawing settings.
|
||||
HandDrawingSettings = FSGDebugGizmoSettings{
|
||||
1.0f,
|
||||
FColor{255, 0, 0, 255},
|
||||
FColor{0, 255, 0, 255},
|
||||
FColor{0, 0, 255, 255},
|
||||
false,
|
||||
1.1f,
|
||||
0,
|
||||
0.2f,
|
||||
};
|
||||
// Set the default virtual hand drawing settings.
|
||||
HandDrawingSettings = FSGDebugGizmoSettings{
|
||||
1.0f,
|
||||
FColor{255, 0, 0, 255},
|
||||
FColor{0, 255, 0, 255},
|
||||
FColor{0, 0, 255, 255},
|
||||
false,
|
||||
1.1f,
|
||||
0,
|
||||
0.2f,
|
||||
};
|
||||
}
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
void ADebugPawn::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
// Called every frame
|
||||
void ADebugPawn::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
// Attempt at drawing the left/right virtual hands every frame.
|
||||
DrawHand(EControllerHand::Left);
|
||||
DrawHand(EControllerHand::Right);
|
||||
// Attempt at drawing the left/right virtual hands every frame.
|
||||
DrawHand(EControllerHand::Left);
|
||||
DrawHand(EControllerHand::Right);
|
||||
}
|
||||
|
||||
// Called to bind functionality to input
|
||||
void ADebugPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
||||
{
|
||||
Super::SetupPlayerInputComponent(PlayerInputComponent);
|
||||
Super::SetupPlayerInputComponent(PlayerInputComponent);
|
||||
}
|
||||
|
||||
void ADebugPawn::DrawHand(const EControllerHand Hand) const
|
||||
{
|
||||
// Get the world and cache it, if it's null we return early.
|
||||
UWorld* World{GetWorld()};
|
||||
if (!IsValid(World))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Get the world and cache it, if it's null we return early.
|
||||
UWorld* World{GetWorld()};
|
||||
if (!IsValid(World))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FXRMotionControllerData MotionControllerData;
|
||||
const bool bGotMotionControllerData = FSGXRTracker::GetMotionControllerData(
|
||||
World, Hand, MotionControllerData);
|
||||
FXRMotionControllerData MotionControllerData;
|
||||
const bool bGotMotionControllerData = FSGXRTracker::GetMotionControllerData(
|
||||
World, Hand, MotionControllerData);
|
||||
|
||||
// Return if the struct data is invalid!
|
||||
if (!bGotMotionControllerData || !MotionControllerData.bValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Return if the struct data is invalid!
|
||||
if (!bGotMotionControllerData || !MotionControllerData.bValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Return if the device is not being tracked!
|
||||
if (MotionControllerData.TrackingStatus == ETrackingStatus::NotTracked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Return if the device is not being tracked!
|
||||
if (MotionControllerData.TrackingStatus == ETrackingStatus::NotTracked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure that MotionControllerData.DeviceVisualType is a hand!
|
||||
if (!ensureAlwaysMsgf(MotionControllerData.DeviceVisualType
|
||||
== EXRVisualType::Hand,
|
||||
TEXT("Invalid DeviceVisualType type!")))
|
||||
{
|
||||
}
|
||||
// Ensure that MotionControllerData.DeviceVisualType is a hand!
|
||||
if (!ensureAlwaysMsgf(MotionControllerData.DeviceVisualType
|
||||
== EXRVisualType::Hand,
|
||||
TEXT("Invalid DeviceVisualType type!")))
|
||||
{
|
||||
}
|
||||
|
||||
// Ensure that MotionControllerData.HandKeyPositions has the position data
|
||||
// for 26 joints!
|
||||
if (!ensureAlwaysMsgf(MotionControllerData.HandKeyPositions.Num()
|
||||
== EHandKeypointCount,
|
||||
TEXT("Invalid HandKeyPositions count!")))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Ensure that MotionControllerData.HandKeyPositions has the position data
|
||||
// for 26 joints!
|
||||
if (!ensureAlwaysMsgf(MotionControllerData.HandKeyPositions.Num()
|
||||
== EHandKeypointCount,
|
||||
TEXT("Invalid HandKeyPositions count!")))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure that MotionControllerData.HandKeyPositions has the rotation data
|
||||
// for 26 joints!
|
||||
if (!ensureAlwaysMsgf(MotionControllerData.HandKeyRotations.Num()
|
||||
== EHandKeypointCount,
|
||||
TEXT("Invalid HandKeyRotations count!")))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Ensure that MotionControllerData.HandKeyRotations has the rotation data
|
||||
// for 26 joints!
|
||||
if (!ensureAlwaysMsgf(MotionControllerData.HandKeyRotations.Num()
|
||||
== EHandKeypointCount,
|
||||
TEXT("Invalid HandKeyRotations count!")))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterate over the hand joint positions and rotations!
|
||||
for (int32 JointIndex = 0; JointIndex < EHandKeypointCount; ++JointIndex)
|
||||
{
|
||||
const FVector& JointPosition{
|
||||
MotionControllerData.HandKeyPositions[JointIndex]
|
||||
};
|
||||
const FQuat& JointRotation{
|
||||
MotionControllerData.HandKeyRotations[JointIndex]
|
||||
};
|
||||
// Iterate over the hand joint positions and rotations!
|
||||
for (int32 JointIndex = 0; JointIndex < EHandKeypointCount; ++JointIndex)
|
||||
{
|
||||
const FVector& JointPosition{
|
||||
MotionControllerData.HandKeyPositions[JointIndex]
|
||||
};
|
||||
const FQuat& JointRotation{
|
||||
MotionControllerData.HandKeyRotations[JointIndex]
|
||||
};
|
||||
|
||||
// Draw a single joint's gizmo!
|
||||
// Please note that we could alternatively:
|
||||
// Use FSGDebugCube::Draw() to draw a cube.
|
||||
// Or use the FSGDebugVirtualHand::Draw() method and pass the
|
||||
// MotionControllerData directly to draw the virtual hand
|
||||
// all at once without iterating the joints. But, that's not
|
||||
// goal of this tutorial.
|
||||
FSGDebugGizmo::Draw(World, JointPosition, JointRotation, HandDrawingSettings);
|
||||
}
|
||||
// Draw a single joint's gizmo!
|
||||
// Please note that we could alternatively:
|
||||
// Use FSGDebugCube::Draw() to draw a cube.
|
||||
// Or use the FSGDebugVirtualHand::Draw() method and pass the
|
||||
// MotionControllerData directly to draw the virtual hand
|
||||
// all at once without iterating the joints. But, that's not
|
||||
// goal of this tutorial.
|
||||
FSGDebugGizmo::Draw(World, JointPosition, JointRotation, HandDrawingSettings);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
15. Now, rebuild the source code and go back to the `VRTemplateMap`, then use the VR Preview button to run the game. If everything's done correctly, you should be able to see the virtual hands inside your VR simulation.
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
This is a bugfix release that delivers some documentation fixes.
|
||||
|
||||
### Documentation
|
||||
|
||||
- Updated the documentation on consuming the `FXRMotionControllerData` struct.
|
||||
- Additional minor documentation fixes and improvements that may not be listed here.
|
||||
|
||||
## [2.1.3] - 2024-10-11
|
||||
|
||||
### Added
|
||||
@@ -722,4 +731,4 @@ This is a minor release focusing on adherence to the Unreal Engine Marketplace G
|
||||
|
||||
### Added
|
||||
|
||||
- Initial public release of the SenseGlove haptic API for Unreal Engine with support for Microsoft Windows and GNU/Linux.
|
||||
- Initial public release of the SenseGlove haptic API for Unreal Engine with support for Microsoft Windows and GNU/Linux.
|
||||
|
||||
Reference in New Issue
Block a user