Motion Controller Input for Player Pawn

 In the last part of the tutorial series, we will look at adding code for input handling on the rift’s motion controller. As with the other parts of the tutorial series, this part builds on top of what we have already achieved in the previous parts.

To recap, we have created the player pawn using mainly C++ for the rift, set up all the necessary components for head and motion controller tracking, added the hand models and animations from the VR template that ships with the engine and hooked then up to the tracked motion controllers. In case you have missed this or haven’t gotten this figured out yet, I suggest that you read those parts before getting to this part of the tutorial. There are breadcrumb links to the previous post as well as links in the tutorials page.

In this part, let’s map the trigger buttons to perform the grip action on the skeletal models that we imported in the previous part of the tutorial. We will do a very simplistic implementation of this for this tutorial. I think that the implementation here will show you enough to take the knowledge and apply it to achieve what you need for your own project.

Input Bindings:

Let’s now start looking into getting the input from the motion controllers. Once we are able to map the input to a specific function, we can go ahead and hook up the input to the animation blueprint. To start accepting the input from the motion controllers, we first need to set-up the Input mapping in the project settings. Below is the set-up.

InputBindings.jpg

Open the project settings from the edit menu in the editor. Open the Input settings using the right tab and edit the bindings as shown on the left.

Code for Input Handling:

Now that the bindings have been set-up we can use them in the player pawn class to bind functions that would be executed when the input occurs. Let’s start by opening the player pawn (c++) class that we have set-up in the previous post.

We start by creating 4 BlueprintNativeEvent functions. These are functions that have native implementation by can also be overridden by a blueprint. This might come in handy later when we might have to do some implementation with the blueprint. For now, the functions will only have a log to debug whether the function is being called when the input is given. We will hook this up to the actual hand animation later in the tutorial.Here are the function declarations that need to be added to the header file.

UFUNCTION (BlueprintNativeEvent, Category = "Input")
void GripLeftHand_Pressed();
UFUNCTION(BlueprintNativeEvent, Category = "Input")
void GripRightHand_Pressed();
UFUNCTION (BlueprintNativeEvent, Category = "Input")
void GripLeftHand_Released();
UFUNCTION(BlueprintNativeEvent, Category = "Input")
void GripRightHand_Released();

In the cpp file for the player pawn, we write the implementation for the input handler functions. Here is the implementation with the debug logs being written.

void AcVRPlayerPawn::GripLeftHand_Pressed_Implementation()
{
    UE_LOG(LogTemp, Log, TEXT("Left Hand Grip Pressed"));
}
void AcVRPlayerPawn::GripRightHand_Pressed_Implementation()
{
    UE_LOG(LogTemp, Log, TEXT("Right Hand Grip Pressed"));
}
void AcVRPlayerPawn::GripLeftHand_Released_Implementation()
{
    UE_LOG(LogTemp, Log, TEXT("Left Hand Grip Released"));
}
void AcVRPlayerPawn::GripRightHand_Released_Implementation()
{
    UE_LOG(LogTemp, Log, TEXT("Left Hand Grip Released"));
}

Since the class derives from the player pawn class we will find that it already contains the function for setting up the input related functionality. This function is called “SetupPlayerInputComponent”. We can now set up this function to call the newly created input handler functions.

void AcVRPlayerPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
InputComponent->BindAction("Grip_Left_Hand", IE_Pressed, this, &AcVRPlayerPawn::GripLeftHand_Pressed);
InputComponent->BindAction("Grip_Right_Hand", IE_Pressed, this, &AcVRPlayerPawn::GripRightHand_Pressed);
InputComponent->BindAction("Grip_Left_Hand", IE_Released, this, &AcVRPlayerPawn::GripLeftHand_Released);
InputComponent->BindAction("Grip_Right_Hand", IE_Released, this, &AcVRPlayerPawn::GripRightHand_Released);
}

We can now test out the functionality that we have so far. If we hit the VR preview (play) button on the editor window (while having the rift and the controllers connected), We can see that the logs are generated when the left and the right triggers are pressed.

Hand Anim Blueprint Base Class:

We will require some functionality of the animation blueprint class to be accessible from the C++ player pawn class. This functionality will be used for setting the grip value that we will get from the motion controller for now. But as we build upon the functionality of the hand it will be very useful to have the base class of the animation blueprint in C++.

Let’s start by creating the base C++ class for the hand animation blueprint. Let’s call this anim instance class cPlayerHandAnimBP.

AnimBlueprintBaseClass.jpg

Next, we need to set the class we just created as the base class for the animation blueprint that we created in the previous post. To do this, open up the animation blueprint and in the editor window click on the “Class Settings” button in the toolbar menu at the top. You should now be able to see the “Parent Class” drop-down menu in the left panel. We click on this and type in the name of the class that we just created. and select it. After this is done let’s compile the blueprint. We now have a c++ animation class that can have variables and functions that we can override and utilize in the blueprint.

We start with some basic functionality that will be used by the pawn class to set the controller grip value which will be used by the animation blueprint to do the grab animation. Here are the header and source files of the class:

UCLASS()
class RIFT_FROM_BLANK_API UcPlayerHandAnimBP : public UAnimInstance
{
    GENERATED_BODY()
    public:
        UcPlayerHandAnimBP(const FObjectInitializer& ObjectInitializer);
        UFUNCTION()
        virtual void SetGripValue(float a_fGrip);
    protected:
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Blend")
        float m_fGripVal;
};
#include "cPlayerHandAnimBP.h"
UcPlayerHandAnimBP::UcPlayerHandAnimBP(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
    //set any default values for your variables here
    m_fGripVal = 0.0f;
}
void UcPlayerHandAnimBP::SetGripValue(float a_fGrip)
{
    m_fGripVal = a_fGrip;
}

Now all we have to do is set up the animation blueprint to use the grip value that is being set in the base class. we add the following functionality to the same animation blueprint that we have created for the hand animation in the previous post. As we can see (in the screenshot below) if the grip float variable is greater than 0.5 we are setting the booleans to true which should activate the grab animation.

AnimationBP_Update.jpg

Caching the Hand Mesh and Animation Blueprint:

Now that the hand blueprint is set up with the required components, we need to edit the player pawn to cache the required components from the hand asset. Let’s start by caching the hand skeletal mesh asset.

Let’s create a couple of private properties in the pawn header file:

USkeletalMeshComponent* m_meshLeftHand;
USkeletalMeshComponent* m_meshRightHand;
Next, we edit the “CreateHandController” function in the player pawn class that we have set up in the post here. Below is the changed function. We are interested in the last 4 lines, rest is the same as before.
void AcVRPlayerPawn::CreateHandController(USceneComponent* a_compParent, FName a_strDisplayName, FName a_nameHandType)
{
UMotionControllerComponent* compMotionController = CreateDefaultSubobject(a_strDisplayName);
compMotionController->SetRelativeLocationAndRotation(FVector::ZeroVector, FQuat::Identity);
compMotionController->SetRelativeScale3D(FVector::OneVector);

compMotionController->MotionSource = a_nameHandType;
compMotionController->SetupAttachment(a_compParent);

//Create the hand mesh for visualization
FName strMeshDisplayName = a_nameHandType == FXRMotionControllerBase::LeftHandSourceId ? FName(TEXT("Hand_Left")) : FName(TEXT("Hand_Right"));
USkeletalMeshComponent* refHandMesh = CreateHandMesh(compMotionController, strMeshDisplayName, a_nameHandType);
if (a_nameHandType == FXRMotionControllerBase::LeftHandSourceId)
m_meshLeftHand = refHandMesh;
else
m_meshRightHand = refHandMesh;
}

Now that we have the reference to the hand mesh we can get the animation instance. Next we can cache the reference to the left and right hand animation instance in the begin play event. First we start by creating the private properties to hold the references.

UcPlayerHandAnimBP* m_refLeftHandAnimBP;
UcPlayerHandAnimBP* m_refRightHandAnimBP;

We will now implement a private function in the pawn class that caches the animation blueprints. This function will be called at the bottom of the BeginPlay() event.

void AcVRPlayerPawn::CacheHandAnimInstances()
{
m_refLeftHandAnimBP = Cast(m_meshLeftHand->GetAnimInstance());
if (!IsValid(m_refLeftHandAnimBP))
UE_LOG(LogTemp, Error, TEXT("Could not cast Hand Anim to the right class"));
m_refRightHandAnimBP = Cast(m_meshRightHand->GetAnimInstance());
if (!IsValid(m_refRightHandAnimBP))
UE_LOG(LogTemp, Error, TEXT("Could not cast Hand Anim to the right class"));
}

 Motion Controller Input To affect Hand animation:

Now we have all the individual pieces of the puzzle in place. We just have to connect the input related code to the animation blueprint function. Let’s do this connection now.

We edit the input functions that we implemented in the start of the post to set the grip value into the right animation blueprint. when the “pressed” action for either of the controller is invoked, we set the grip value on the relevant animation blueprint to 1.0 and when the “released” action is invoked we set the grip value to 0.0. The way we should be able to see the animation play out when the trigger is pressed on the motion controller. Here are the edited input functions:

void AcVRPlayerPawn::GripLeftHand_Pressed_Implementation()
{
UE_LOG(LogTemp, Log, TEXT("Left Hand Grip Pressed"));
m_refLeftHandAnimBP->SetGripValue(1.0f);
}

void AcVRPlayerPawn::GripRightHand_Pressed_Implementation()
{
UE_LOG(LogTemp, Log, TEXT("Right Hand Grip Pressed"));
m_refRightHandAnimBP->SetGripValue(1.0f);
}

void AcVRPlayerPawn::GripLeftHand_Released_Implementation()
{
UE_LOG(LogTemp, Log, TEXT("Left Hand Grip Released"));
m_refLeftHandAnimBP->SetGripValue(0.0f);
}

void AcVRPlayerPawn::GripRightHand_Released_Implementation()
{
UE_LOG(LogTemp, Log, TEXT("Left Hand Grip Released"));
m_refRightHandAnimBP->SetGripValue(0.0f);
}

Its time to test the implementation. I will post the video below with the hand animation working in the editor as well as the build. With this we can conclude the series. We have sen the basics of setting up the unreal project for VR development ffrom scratch and not using the template. If you haven’t seen the tutorial series from start or if you want to explore other tutorials, please visit the tutorials page.

Please leave any comments that you might have regarding the series or any topics that you would like me to get into in the comments section below.

7 thoughts on “Motion Controller Input for Player Pawn

  1. Hi I am currently trying to SetAnimInstanceClass() for my mesh and it is not working. Maybe this tutorial is a bit outdated? My code is:

    SetAnimInstanceClass(HandAnimBP.Object->GetAnimBlueprintGeneratedClass());

    I am calling FObjectFinder to get the UAnimBlueprint and it finds it, but when I call GetAnimInstance() it always comes up as invalid.

    1. I fixed this by just setting the animinstanceclass in my character blueprint.

      But I am having trouble with your code:

      m_refLeftHandAnimBP = Cast(m_meshLeftHand->GetAnimInstance());

      I think that casting is outdated, but when I try:

      = (UcPlayerHandAnimBP*)m_meshLeftHand->GetAnimInstance();

      It doesn’t work. Can you help me with this? Thanks.

      1. Sorry about the late reply. If you haven’t solved it yet, could you please try the following code?

        m_refLeftHandAnimBP = Cast(m_meshLeftHand->GetAnimInstance());

        Also please let me know the version of UE4 you are using.

  2. Hey DarkRyder! Thank you so much for this tutorial, it has been extremely helpful. I am having issues implementing the grip animation, where my engine crashes with an EXCEPTION_ACCESS_VIOLATION when calling the SetGripValue() function, i.e. :

    m_refRightHandAnimBP->SetGripValue(1.0f);

    The only part in which my code differs from yours is during casting, as I used:

    m_refLeftHandAnimBP = (UcPlayerHandAnimBP*)(m_meshLeftHand->GetAnimInstance());

    Any ideas as to what may be happening?

    Thank you again!

    1. Hey Nick,
      Glad that you are finding the tutorial helpful.
      Can you please tell me what’s the version of UE4 that you are running?
      I did find that you need to cast in the later version of the engine. The other thing that I can think of that that the AnimInstance is null.
      Could you please check that it is being assigned?

      Also, Could you please checkout the git repository and see if that is working for you?

Leave a Reply to Skout Roberson Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.