Download

Oculus dk2 + Oculus touch controls [Solved]

Hello!
I make controls for Oculus dk2 + Oculus touch. Moving by MotionController(R) Thumbstic X and Y, turning by MotionController(L) Thumbstic X. Grabing by MotionController Grip1 for R and L hands respectively.
I have a problem: when I try pressed grab button and moving, player moving very strange - changing directions and speed.
Code:
[SPOILER]
VRCharacter.h[SPOILER]



#pragma once

#include "GameFramework/Character.h"
#include "VRCharacter.generated.h"

UCLASS()
class VRFIRSTPERSON_API AVRCharacter : public ACharacter
{
    GENERATED_BODY()

protected:

    UPROPERTY(VisibleAnywhere, Category = "Components")
    UCameraComponent* CameraComp;

    /* Component to specify origin for the HMD */
    UPROPERTY(VisibleAnywhere, Category = "Components")
    USceneComponent* VROriginComp;

    UPROPERTY(EditDefaultsOnly, Category = "VR")
    bool bPositionalHeadTracking;

    /* Motion Controllers */

    UPROPERTY(EditDefaultsOnly, Category = "Components")
    class UChildActorComponent* LeftHandComponent;

    UPROPERTY(EditDefaultsOnly, Category = "Components")
    class UChildActorComponent* RightHandComponent;

public:
    // Sets default values for this character's properties
    AVRCharacter();

    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* InputComponent) override;

    void SetupVROptions();

    /* Resets HMD Origin position and orientation */
    void ResetHMDOrigin();

    /* Toggle between Seated and Standing VR Tracking */
    void ToggleTrackingSpace();

    void HandleLeftPress();
    void HandleLeftRelease();

    void HandleRightPress();
    void HandleRightRelease();

private:
    void MoveForward(float Value);
    void MoveRight(float Value);    
};


[/SPOILER]

VRCharacter.cpp [SPOILER]



#include "VRFirstPerson.h"

/* VR Includes */
#include "HeadMountedDisplay.h"
#include "MotionControllerComponent.h"
#include "VRHand.h"
#include "VRCharacter.h"


// Sets default values
AVRCharacter::AVRCharacter()
{
     // Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    VROriginComp = CreateDefaultSubobject<USceneComponent>(TEXT("VRCameraOrigin"));
    VROriginComp->SetupAttachment(RootComponent);

    CameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));
    /* Assign to the VR origin component so any reset calls to the HMD can reset to 0,0,0 relative to this component */
    CameraComp->SetupAttachment(VROriginComp);

    LeftHandComponent = CreateDefaultSubobject<UChildActorComponent>(TEXT("LeftHand"));
    //LeftHandComponent->Hand = EControllerHand::Left;
    LeftHandComponent->SetupAttachment(VROriginComp);

    RightHandComponent = CreateDefaultSubobject<UChildActorComponent>(TEXT("RightHand"));
    //RightHandComponent->Hand = EControllerHand::Right;
    RightHandComponent->SetupAttachment(VROriginComp);

    bPositionalHeadTracking = false;


}

// Called when the game starts or when spawned
void AVRCharacter::BeginPlay()
{
    Super::BeginPlay();

    SetupVROptions();

    //AVRHand *LCurrent = Cast<AVRHand>(LeftHandComponent->GetChildActor());
    //if (LCurrent)
    //{
    //    LCurrent->SetOwnerChar(this);
    //}

    //AVRHand *RCurrent = Cast<AVRHand>(RightHandComponent->GetChildActor());
    //if (RCurrent)
    //{
    //    RCurrent->SetOwnerChar(this);
    //}
}

// Called to bind functionality to input
void AVRCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    PlayerInputComponent->BindAction("ToggleTrackingSpace", IE_Pressed, this, &AVRCharacter::ToggleTrackingSpace);
    PlayerInputComponent->BindAction("ResetHMDOrigin", IE_Pressed, this, &AVRCharacter::ResetHMDOrigin);

    PlayerInputComponent->BindAxis("MoveForward", this, &AVRCharacter::MoveForward);
    PlayerInputComponent->BindAxis("MoveRight", this, &AVRCharacter::MoveRight);

    PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);

    PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
    PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);

    PlayerInputComponent->BindAction("GrabLeft", IE_Pressed, this, &AVRCharacter::HandleLeftPress);
    PlayerInputComponent->BindAction("GrabLeft", IE_Released, this, &AVRCharacter::HandleLeftRelease);
    PlayerInputComponent->BindAction("GrabRigjt", IE_Pressed, this, &AVRCharacter::HandleRightPress);
    PlayerInputComponent->BindAction("GrabRigjt", IE_Released, this, &AVRCharacter::HandleRightRelease);
}

void AVRCharacter::MoveForward(float Value)
{
    if (Value != 0.0f)
    {
        // add movement in that direction
        AddMovementInput(GetActorForwardVector(), Value);
    }
}

void AVRCharacter::MoveRight(float Value)
{
    if (Value != 0.0f)
    {
        // add movement in that direction
        AddMovementInput(GetActorRightVector(), Value);
    }
}

void AVRCharacter::SetupVROptions()
{
    IHeadMountedDisplay* HMD = (IHeadMountedDisplay*)(GEngine->HMDDevice.Get());
    if (HMD && HMD->IsStereoEnabled())
    {
        /* Disable/Enable positional movement to pin camera translation */
        HMD->EnablePositionalTracking(bPositionalHeadTracking);

        /* Remove any translation when disabling positional head tracking */
        if (!bPositionalHeadTracking)
        {
            CameraComp->SetRelativeLocation(FVector(0, 0, 0));
        }
    }
}


void AVRCharacter::ResetHMDOrigin()
{
    IHeadMountedDisplay* HMD = (IHeadMountedDisplay*)(GEngine->HMDDevice.Get());
    if (HMD && HMD->IsStereoEnabled())
    {
        HMD->ResetOrientationAndPosition();
    }
}


void AVRCharacter::ToggleTrackingSpace()
{
    // TODO: Fix module includes for SteamVR

    //@todo Make this safe once we can add something to the DeviceType enum.  For now, make the terrible assumption this is a SteamVR device.
//     FSteamVRHMD* SteamVRHMD = (FSteamVRHMD*)(GEngine->HMDDevice.Get());
//     if (SteamVRHMD && SteamVRHMD->IsStereoEnabled())
//     {
//         ESteamVRTrackingSpace TrackingSpace = SteamVRHMD->GetTrackingSpace();
//         SteamVRHMD->SetTrackingSpace(TrackingSpace == ESteamVRTrackingSpace::Seated ? ESteamVRTrackingSpace::Standing : ESteamVRTrackingSpace::Seated);
//     }
}


void AVRCharacter::HandleLeftPress()
{
    AVRHand *Current = Cast<AVRHand>(LeftHandComponent->GetChildActor());
    if (Current)
    {
        Current->GrabActor();
    }
}

void AVRCharacter::HandleLeftRelease()
{
    AVRHand *Current = Cast<AVRHand>(LeftHandComponent->GetChildActor());
    if (Current)
    {
        Current->ReleaseActor();
    }
}

void AVRCharacter::HandleRightPress()
{
    AVRHand *Current = Cast<AVRHand>(RightHandComponent->GetChildActor());
    if (Current)
    {
        Current->GrabActor();
    }
}

void AVRCharacter::HandleRightRelease()
{
    AVRHand *Current = Cast<AVRHand>(RightHandComponent->GetChildActor());
    if (Current)
    {
        Current->ReleaseActor();
    }
}


[/SPOILER]

VRHand.h [SPOILER]



#pragma once

#include "GameFramework/Actor.h"
#include "VRCharacter.h"
#include "VRHand.generated.h"

UENUM(BlueprintType)
enum class EGripState : uint8
{
    Open,
    Index,
    CanGrab,
    Grab
};

UCLASS()
class VRFIRSTPERSON_API AVRHand : public AActor
{
    GENERATED_BODY()

    UPROPERTY( VisibleAnywhere, BlueprintReadOnly, Category = "Code Components", meta = ( AllowPrivateAccess = "true" ) )
    class USceneComponent *Scene;

    UPROPERTY( VisibleAnywhere, BlueprintReadOnly, Category = "Code Components", meta = (AllowPrivateAccess = "true"))
    class UMotionControllerComponent *MotionController;

    UPROPERTY( VisibleAnywhere, BlueprintReadOnly, Category = "Code Components", meta = (AllowPrivateAccess = "true"))
    class USkeletalMeshComponent *HandMesh;

    UPROPERTY( VisibleAnywhere, BlueprintReadOnly, Category = "Code Components", meta = ( AllowPrivateAccess = "true" ) )
    class USphereComponent *GrabSphere;

    UPROPERTY( VisibleAnywhere, BlueprintReadOnly, Category = "Code Components", meta = ( AllowPrivateAccess = "true" ) )
    class USplineComponent *ArcSpline;

    UPROPERTY( VisibleAnywhere, BlueprintReadOnly, Category = "Code Components", meta = ( AllowPrivateAccess = "true" ) )
    class UArrowComponent *ArcDirection;

    FRotator InitialControllerRotation;
    TArray<class USplineMeshComponent*> SplineMeshes;

public:    
    AVRHand();

    virtual void BeginPlay() override;
    virtual void Tick(float DeltaTime) override;
    virtual void OnConstruction(const FTransform & Transform) override;



    /** Is this the left or right hand */
    UPROPERTY( EditAnywhere, BlueprintReadWrite, Category = "Code Constants" )
    EControllerHand Hand;

    UPROPERTY( EditAnywhere, BlueprintReadWrite, Category = "Code Constants" )
    FVector Extents;

    UPROPERTY( EditAnywhere, BlueprintReadWrite, Category = "Code Variables" )
    bool WantsToGrip;

    UPROPERTY( EditAnywhere, BlueprintReadWrite, Category = "Code Variables" )
    EGripState Grip;

    UPROPERTY( EditAnywhere, BlueprintReadWrite, Category = "Code Variables" )
    class AActor *AttachedActor;

    UFUNCTION()
    void OnComponentBeginOverlap( UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult );

    UFUNCTION( BlueprintNativeEvent, BlueprintCallable, Category = "Default" )
    void RumbleController( float intensity );

    UFUNCTION( BlueprintNativeEvent, BlueprintCallable, Category = "Default" )
    void GrabActor();

    UFUNCTION( BlueprintNativeEvent, BlueprintCallable, Category = "Default" )
    void ReleaseActor();

    //void SetOwnerChar(AVRCharacter* OwnerChar);

    AActor* GetActorNearHand();
    void UpdateAnimationGripState();

    FRotator GetControllerRelativeRotation();

//private:
//    AVRCharacter* OwnerChar;
};


[/SPOILER]

VRHand.cpp [SPOILER]



#include "VRFirstPerson.h"
#include "VRHand.h"

#include "IPickupable.h"
#include "HeadMountedDisplay.h"
#include "MotionControllerComponent.h"
#include "Runtime/Engine/Classes/Kismet/HeadMountedDisplayFunctionLibrary.h"
#include "Runtime/Engine/Classes/Components/SplineComponent.h"
#include "Runtime/HeadMountedDisplay/Public/IHeadMountedDisplay.h"
#include "Runtime/Engine/Classes/Kismet/KismetMathLibrary.h"
#include "Runtime/Engine/Classes/Components/SplineMeshComponent.h"


// Sets default values
AVRHand::AVRHand()
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    Hand = EControllerHand::Right;
    Grip = EGripState::Open;

    Scene = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));

    MotionController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("MotionController"));
    MotionController->SetupAttachment(Scene);
    MotionController->Hand = Hand;

    HandMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("HandMesh"));
    HandMesh->SetupAttachment(MotionController);

    GrabSphere = CreateDefaultSubobject<USphereComponent>(TEXT("GrabSphere"));
    GrabSphere->SetupAttachment(HandMesh);
    GrabSphere->InitSphereRadius(10.0f);
    GrabSphere->OnComponentBeginOverlap.AddDynamic(this, &AVRHand::OnComponentBeginOverlap);

    ArcDirection = CreateDefaultSubobject<UArrowComponent>(TEXT("ArcDirection"));
    ArcDirection->SetupAttachment(HandMesh);

    ArcSpline = CreateDefaultSubobject<USplineComponent>(TEXT("ArcSpline"));
    ArcSpline->SetupAttachment(HandMesh);
}

void AVRHand::OnConstruction(const FTransform & Transform)
{
    Super::OnConstruction(Transform);

    if (Hand == EControllerHand::Left)
    {
        // Reflect hand mesh
        HandMesh->SetWorldScale3D(FVector(1, 1, -1));
    }
}

void AVRHand::RumbleController_Implementation(float intensity)
{
    FLatentActionInfo actionInfo;
    actionInfo.CallbackTarget = this;
    APlayerController *playerController = GetWorld()->GetFirstPlayerController();
}

void AVRHand::OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
    if (OtherActor->IsA(AVRCharacter::StaticClass()))
    {
        return;
    }
    UE_LOG(LogTemp, Warning, TEXT("start"));
    Grip = EGripState::CanGrab;
    if ((OtherComp != nullptr) && (OtherComp != GrabSphere))
    {
        UE_LOG(LogTemp, Warning, TEXT("if 1"));
        UStaticMeshComponent *mesh = Cast<UStaticMeshComponent>(OtherComp);
        if (mesh && mesh->IsSimulatingPhysics())
        {
            UE_LOG(LogTemp, Warning, TEXT("if 2"));
            this->RumbleController(0.8);
        }
    }
}

// Called when the game starts or when spawned
void AVRHand::BeginPlay()
{
    Super::BeginPlay();

    MotionController->Hand = Hand;
    if (Hand == EControllerHand::Left)
    {
        // Reflect hand mesh
        MotionController->Hand = Hand;
        HandMesh->SetWorldScale3D(FVector(1, 1, -1));
    }

    // Hide until activation (but wait for BeginPlay so it is shown in editor)
}

AActor* AVRHand::GetActorNearHand()
{
    TArray<AActor*> overlappingActors;

    GrabSphere->GetOverlappingActors(overlappingActors);
    FVector handLocation = GrabSphere->GetComponentLocation();

    AActor* nearest = nullptr;
    float mindist = 99999999999;

    // Find closest overlaping actor
    for (AActor *actor : overlappingActors)
    {
        bool isPickupable = actor->GetClass()->ImplementsInterface(UPickupable::StaticClass());
        if (isPickupable)
        {
            //UE_LOG(LogTemp, Warning, TEXT("isPickupable"));
            float dist = (actor->GetActorLocation() - handLocation).SizeSquared();
            if (dist < mindist)
            {
                mindist = dist;
                nearest = actor;
            }
        }
    }

    //     if ( GEngine && Hand == EControllerHand::Right )
    //         GEngine->AddOnScreenDebugMessage( -1, 0.16f, FColor::Red,
    //             FString::Printf( TEXT( "Actors near right hand %d, found pickupable: %d, %s" ),
    //             overlappingActors.Num(),
    //             count,
    //             nearest ? TEXT( "TRUE" ) : TEXT( "FALSE" ) ) );

    return nearest;
}

void AVRHand::UpdateAnimationGripState()
{
    // Default to Open
    Grip = EGripState::Open;

    if (AttachedActor)
    {
        // If holding an object, always keep fist closed
        Grip = EGripState::Grab;
    }
    else
    {
        // React to player input
        if (WantsToGrip)
        {
            Grip = EGripState::Grab;
        }

        // If not holding something, the hand should open or close
        // slightly when passing over an interactable object
        AActor *actor = GetActorNearHand();
        if (actor)
        {
            Grip = EGripState::CanGrab;
        }
    }

    // Only let hand collide with environment while gripping
    if (Grip == EGripState::Grab)
    {
        HandMesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
    }
    else
    {
        HandMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
    }
}

void AVRHand::GrabActor_Implementation()
{
    WantsToGrip = true;

    AActor *actor = GetActorNearHand();

    if (actor && actor->IsValidLowLevel())
    {
        UE_LOG(LogTemp, Warning, TEXT("IsValidLowLevel"));
        AttachedActor = actor;
        IPickupable::Execute_Pickup(actor, MotionController);
        RumbleController(0.7);
    }
}

void AVRHand::ReleaseActor_Implementation()
{
    WantsToGrip = false;

    AActor *actor = AttachedActor;
    if (actor && actor->IsValidLowLevel())
    {
        // Make sure this hand is still holding the Actor (May have been taken by another hand / event)
        if (MotionController == actor->GetRootComponent()->GetAttachParent())
        {
            IPickupable::Execute_Drop(actor);
            RumbleController(0.2);
        }
    }

    AttachedActor = nullptr;
}

// Called every frame
void AVRHand::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    UpdateAnimationGripState();
}

FRotator AVRHand::GetControllerRelativeRotation()
{
    const FTransform InitialTransform(InitialControllerRotation);
    const FTransform CurrentTransform = MotionController->GetComponentTransform();
    const FTransform RelativeTransform = CurrentTransform.GetRelativeTransform(InitialTransform);

    return RelativeTransform.GetRotation().Rotator();
}

//void AVRHand::SetOwnerChar(AVRCharacter* OwnerChar)
//{
//    this->OwnerChar = OwnerChar;
//
//    if (OwnerChar != nullptr)
//    {
//        GrabSphere->IgnoreActorWhenMoving(OwnerChar, true);
//    }
//}


[/SPOILER]
[/SPOILER]

Can someone help to understand what I doing wrong?

I was under the impression that you could not use the Oculus Touch with the DK2 because they connect to the CV1 via bluetooth, something the DK2 does not have and is currently impossible to emulate on the PC with a dongle. Also I believe the touch requires at least two sensors and the DK2 only has one.

I have two sensors. In games and demos I haven’t any problem with Oculus Touch + DK2, its working perfectly. In UE Virtual Reality template its working perfecttly. I have a problem only in my project when pressed grab button and moving.

Solve was found in Thumbstick movement with Touch issue - VR and AR Development - Unreal Engine Forums
I rewrited blueprints from post #8 in c++ code and now controls working great.

Man, how did you manage that? Everyone says that DC2 and Touch do not work together.