Oculus Rift Separate View

From Epic Wiki

Overview

By default, using an in Unreal Engine 4 affects the rotation responsible for both the players view and movement direction.

There are two main ways to change this:

  • Creating a Player Camera Manager, Player Controller & GameMode using Blueprints.
  • Creating a new Player Controller, Character & GameMode in C++.

The end results are similar - the players view and movement directions are separate - but the C++ version is more flexible.

Blueprints

  1. Create a Blueprint that based on PlayerCameraManager.
  2. In the Defaults tab, find "Follow Hmd Orientation" and set it to "true".
  3. Create a Blueprint that based on PlayerController.
  4. In the Defaults tab, find Player Camera Manager Class and set it to your PlayerCameraManager Blueprint.
  5. Create a Blueprint that based on GameMode.
  6. In the Defaults tab, find Default Controller Class and set it to your PlayerController Blueprint.
  7. Finally, under your levels World Settings, find GameMode Override and set it to your GameMode Blueprint.

C++

The C++ method is a more complex, but is also more flexible.

Your.Build.cs

Add HeadMountedDisplay to PublicDependencyModuleNames.

        PublicDependencyModuleNames.AddRange(new string[] { 
            "Core", 
            "CoreUObject",
            "Engine",
            "InputCore", 
            "HeadMountedDisplay"
        });
});

YourPlayerController.h

    virtual void UpdateRotation(float DeltaTime) override;
    
    UFUNCTION(BlueprintCallable, Category="Pawn")
    FRotator GetViewRotation() const;

    UFUNCTION(BlueprintCallable, Category="Pawn")
    virtual void SetViewRotation(const FRotator& NewRotation);
    
    virtual void SetControlRotation(const FRotator& NewRotation) override;
    
protected:

    /**
     *  View & Movement direction are now separate.
     *  The controller rotation will determine which direction we will move.
     *  ViewRotation represents where we are looking.
     */
    UPROPERTY()
    FRotator ViewRotation;

YourPlayerController.cpp

// Make sure you include this!!
#include "IHeadMountedDisplay.h"

void AYourPlayerController::UpdateRotation(float DeltaTime)
{
    // Calculate Delta to be applied on ViewRotation
    FRotator DeltaRot(RotationInput);

    FRotator NewControlRotation = GetControlRotation();

    if (PlayerCameraManager)
    {
        PlayerCameraManager->ProcessViewRotation(DeltaTime, NewControlRotation, DeltaRot);
    }

    SetControlRotation(NewControlRotation);

    if (!PlayerCameraManager || !PlayerCameraManager->bFollowHmdOrientation)
    {
        if (GEngine->HMDDevice.IsValid() && GEngine->HMDDevice->IsHeadTrackingAllowed())
        {
            FQuat HMDOrientation;
            FVector HMDPosition;

            // Disable bUpdateOnRT if using this method.
            GEngine->HMDDevice->GetCurrentOrientationAndPosition(HMDOrientation, HMDPosition);

            FRotator NewViewRotation = HMDOrientation.Rotator();

            // Only keep the yaw component from the controller.
            NewViewRotation.Yaw += NewControlRotation.Yaw;
            
            SetViewRotation(NewViewRotation);
        }
    }
    
    APawn* const P = GetPawnOrSpectator();
    if (P)
    {
        P->FaceRotation(NewControlRotation, DeltaTime);
    }
}

void AYourPlayerController::SetControlRotation(const FRotator& NewRotation)
{
    ControlRotation = NewRotation;
    
    // Anything that is overriding view rotation will need to 
    // call SetViewRotation() after SetControlRotation().
    SetViewRotation(NewRotation);
    
    if (RootComponent && RootComponent->bAbsoluteRotation)
    {
        RootComponent->SetWorldRotation(GetControlRotation());
    }
}

void AYourPlayerController::SetViewRotation(const FRotator& NewRotation)
{
    ViewRotation = NewRotation;
}

FRotator AYourPlayerController::GetViewRotation() const
{
    return ViewRotation;
}

YourCharacter.h

public:
    virtual FRotator GetViewRotation() const override;

YourCharacter.cpp

FRotator AYourCharacter::GetViewRotation() const
{
    if (AYourPlayerController* MYPC = Cast<AYourPlayerController>(Controller))
    {
        return MYPC->GetViewRotation();
    }
    else if (Role < ROLE_Authority)
    {
        // check if being spectated
        for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator)
        {
            APlayerController* PlayerController = *Iterator;
            if (PlayerController && PlayerController->PlayerCameraManager->GetViewTargetPawn() == this)
            {
                return PlayerController->BlendedTargetViewRotation;
            }
        }
    }

    return GetActorRotation();
}

YourGameMode.cpp

AYourGameMode::AYourGameMode(const class FPostConstructInitializeProperties& PCIP)
    : Super(PCIP)
{
    DefaultPawnClass = AYourCharacter::StaticClass();
    PlayerControllerClass = AYourPlayerController::StaticClass();
}

See also