diff --git a/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-add-class-choose-name.png b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-add-class-choose-name.png
new file mode 100644
index 00000000..15cab892
--- /dev/null
+++ b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-add-class-choose-name.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2cde517c4eb6ba807f24b7f3b861c62b69501ac4ea94b9e6d1d112af860619ab
+size 35036
diff --git a/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-add-class-choose-parent.png b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-add-class-choose-parent.png
new file mode 100644
index 00000000..eb02fdd0
--- /dev/null
+++ b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-add-class-choose-parent.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:48f0228ee4da1dee629e65f71fefcbe00ab5a52afa8685a3549fc9a4b0143534
+size 38449
diff --git a/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-new-class.png b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-new-class.png
new file mode 100644
index 00000000..8c2e2237
--- /dev/null
+++ b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-new-class.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7f5c77bab4ac3926bc4292203a1c5684928eb7915e9278739e0f532b9e3b04a1
+size 145613
diff --git a/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-reparent-debug-pawn.png b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-reparent-debug-pawn.png
new file mode 100644
index 00000000..d04f9b4c
--- /dev/null
+++ b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-reparent-debug-pawn.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:72e5a568596914ccda9e964387c4bda765707c1bace599f0f89b5aed9cf75df6
+size 8368
diff --git a/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-reparent.png b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-reparent.png
new file mode 100644
index 00000000..a3941609
--- /dev/null
+++ b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-reparent.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3bd9b7c5dafd7ff61cb091851f007ae35745201146fe356b3451b704243a92f3
+size 46779
diff --git a/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-verify-parent-class.png b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-verify-parent-class.png
new file mode 100644
index 00000000..d06d9fe5
--- /dev/null
+++ b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/consuming-fxrmotioncontrollerdata-cpp-verify-parent-class.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:16686ddeefb5375f4e3ed668ebdb61263bf3b98e8bec428b8edf915f75e467df
+size 24869
diff --git a/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/cpp.md b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/cpp.md
index 51364970..646a60a9 100644
--- a/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/cpp.md
+++ b/Handbook/src/advanced-topics/openxr/consuming-fxrmotioncontrollerdata/cpp.md
@@ -2,3 +2,250 @@
Before continuing this section, please ensure you've first studied the [Consuming FXRMotionControllerData](README.md) section.
+## Drawing and Animating Virtual Hands
+
+1. Create a new Virtual Reality project based [the Unreal VR Template](https://dev.epicgames.com/documentation/en-us/unreal-engine/vr-template-in-unreal-engine).
+
+2. Make sure the [SenseGlove UnrealEngine plugin is installed and enabled](/getting-started/installation.md) inside your new project.
+
+
+
+3. You could use either hand-tracking or a SenseGlove device as the input data, or both of the inside the same project. Whether you would like to use hand-tracking or a SenseGlove device, please make sure the required steps are taken for each of those first.
+
+4. From the Tools menu choose New C++ class....
+
+
+
+5. Choose the Unreal Engine's APawn class as the parent class for the new C++ pawn class.
+
+
+
+6. Name the new pawn class DebugPawn.
+
+
+
+7. Since we have created a new C++ class, this converts the current Blueprint VRTemplateMap project to a C++ one. That's why the Unreal Editor will give us a few prompts regarding opening the project in the default IDE and rebuilding the code. It might be simpler to just close the editor, then rebuild the source code inside your favorite IDE, and then start the editor with the converted project again.
+
+8. Find and open the VRPawn Blueprint Class located at /Content/VRTemplate/Blueprints/VRPawn inside the Blueprint Editor and from the File menu choose the Reparent Blueprint class.
+
+
+
+9. In the new Reparent blueprint window choose DebugPawn as the new parent.
+
+
+
+10. By looking at the Parent Class label located under the Blueprint Editor window control buttons verify that the ADebugPawn class has been set as the new parent.
+
+
+
+11. Locate the project's main Build file, in our case VirtualHandCpp/Source/VirtualHandCpp/VirtualHandCpp.Build.cs and add the InputDevice, OpenXRHMD, SenseGloveBuildHacks, SenseGloveDebug, SenseGloveSettings, and SenseGloveTracking modules as either a private or public dependency.
+
+```csharp
+// Fill out your copyright notice in the Description page of Project Settings.
+
+using UnrealBuildTool;
+
+public class VirtualHandCpp : ModuleRules
+{
+ 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"
+ });
+
+ // 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
+ }
+}
+```
+
+12. Locate the C++ header and source file for the ADebugPawn inside the project in your C++ IDE. In our case they are located at VirtualHandCpp/Source/VirtualHandCpp/DebugPawn.h and VirtualHandCpp/Source/VirtualHandCpp/DebugPawn.cpp.
+
+13. Modify the DebugPawn.h header file to look like this:
+
+```cpp
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "GameFramework/Pawn.h"
+
+#include "SGSettings/SGDebugGizmoSettings.h"
+
+#include "DebugPawn.generated.h"
+
+UCLASS()
+class VIRTUALHANDCPP_API ADebugPawn : public APawn
+{
+ GENERATED_BODY()
+
+private:
+ // The virtual hand drawing settings.
+ UPROPERTY(EditDefaultsOnly, Category="DebugPawn")
+ FSGDebugGizmoSettings HandDrawingSettings;
+
+public:
+ // Sets default values for this pawn's properties
+ ADebugPawn();
+
+protected:
+ // Called when the game starts or when spawned
+ virtual void BeginPlay() override;
+
+public:
+ // Called every frame
+ virtual void Tick(float DeltaTime) 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;
+};
+```
+
+14. Modify the DebugPawn.cpp implementation file to look like this:
+
+
+```cpp
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "DebugPawn.h"
+
+#include "SGDebug/SGDebugGizmo.h"
+#include "SGTracking/SGXRTracker.h"
+
+// 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 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();
+}
+
+// Called every frame
+void ADebugPawn::Tick(float DeltaTime)
+{
+ Super::Tick(DeltaTime);
+
+ // 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);
+}
+
+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;
+ }
+
+ 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 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.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;
+ }
+
+ // 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);
+ }
+}
+```
+
+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.
+
+
\ No newline at end of file