Files
UnrealEngineUWP/Engine/Source/Runtime/HeadMountedDisplay/Private/DefaultXRCamera.cpp
jules blok 732e637f62 Fix renderer issues when rendering multiple ISR passes.
- New functions are added to get the Primary View or all Secondary Views and takes advantage of that to replace hardcoded indices.
- Added support for retrieving a monoscopic projection/pose from IStereoRendering when a single frustum is needed for culling purposes.

#rb Steve.Smith
#rb Jeff.Fisher
#rb Zach.Bethel
#preflight 61de16e96a076ddb53cf59b4

#ROBOMERGE-AUTHOR: jules.blok
#ROBOMERGE-SOURCE: CL 18579012 in //UE5/Release-5.0/... via CL 18579021 via CL 18579025
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Test -> Main) (v899-18417669)

[CL 18579042 by jules blok in ue5-main branch]
2022-01-11 19:03:42 -05:00

227 lines
8.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DefaultXRCamera.h"
#include "GameFramework/PlayerController.h"
#include "RendererPrivate.h"
#include "ScenePrivate.h"
#include "Slate/SceneViewport.h"
#include "StereoRendering.h"
#include "StereoRenderTargetManager.h"
#include "IHeadMountedDisplay.h"
FDefaultXRCamera::FDefaultXRCamera(const FAutoRegister& AutoRegister, IXRTrackingSystem* InTrackingSystem, int32 InDeviceId)
: FHMDSceneViewExtension(AutoRegister)
, TrackingSystem(InTrackingSystem)
, DeviceId(InDeviceId)
, DeltaControlRotation(0, 0, 0)
, DeltaControlOrientation(FQuat::Identity)
, bUseImplicitHMDPosition(false)
{
}
void FDefaultXRCamera::ApplyHMDRotation(APlayerController* PC, FRotator& ViewRotation)
{
ViewRotation.Normalize();
FQuat DeviceOrientation;
FVector DevicePosition;
if ( TrackingSystem->GetCurrentPose(DeviceId, DeviceOrientation, DevicePosition) )
{
const FRotator DeltaRot = ViewRotation - PC->GetControlRotation();
DeltaControlRotation = (DeltaControlRotation + DeltaRot).GetNormalized();
// Pitch from other sources is never good, because there is an absolute up and down that must be respected to avoid motion sickness.
// Same with roll.
DeltaControlRotation.Pitch = 0;
DeltaControlRotation.Roll = 0;
DeltaControlOrientation = DeltaControlRotation.Quaternion();
ViewRotation = FRotator(DeltaControlOrientation * DeviceOrientation);
}
}
bool FDefaultXRCamera::UpdatePlayerCamera(FQuat& CurrentOrientation, FVector& CurrentPosition)
{
FQuat DeviceOrientation;
FVector DevicePosition;
if (!TrackingSystem->GetCurrentPose(DeviceId, DeviceOrientation, DevicePosition))
{
return false;
}
if (GEnableVREditorHacks && !bUseImplicitHMDPosition)
{
DeltaControlOrientation = CurrentOrientation;
DeltaControlRotation = DeltaControlOrientation.Rotator();
}
CurrentPosition = DevicePosition;
CurrentOrientation = DeviceOrientation;
return true;
}
void FDefaultXRCamera::OverrideFOV(float& InOutFOV)
{
// The default camera does not override the FOV
}
void FDefaultXRCamera::SetupLateUpdate(const FTransform& ParentToWorld, USceneComponent* Component, bool bSkipLateUpdate)
{
LateUpdate.Setup(ParentToWorld, Component, bSkipLateUpdate);
}
void FDefaultXRCamera::CalculateStereoCameraOffset(const int32 ViewIndex, FRotator& ViewRotation, FVector& ViewLocation)
{
FQuat EyeOrientation;
FVector EyeOffset;
if (TrackingSystem->GetRelativeEyePose(DeviceId, ViewIndex, EyeOrientation, EyeOffset))
{
ViewLocation += ViewRotation.Quaternion().RotateVector(EyeOffset);
ViewRotation = FRotator(ViewRotation.Quaternion() * EyeOrientation);
}
else if (ViewIndex == EStereoscopicEye::eSSE_MONOSCOPIC && TrackingSystem->GetHMDDevice())
{
float HFov, VFov;
TrackingSystem->GetHMDDevice()->GetFieldOfView(HFov, VFov);
if (HFov > 0.0f)
{
const float CenterOffset = GNearClippingPlane + (TrackingSystem->GetHMDDevice()->GetInterpupillaryDistance() / 2.0f) * (1.0f / FMath::Tan(FMath::DegreesToRadians(HFov)));
ViewLocation += ViewRotation.Quaternion().RotateVector(FVector(CenterOffset, 0, 0));
}
}
else
{
return;
}
if (!bUseImplicitHMDPosition)
{
FQuat DeviceOrientation; // Unused
FVector DevicePosition;
TrackingSystem->GetCurrentPose(DeviceId, DeviceOrientation, DevicePosition);
ViewLocation += DeltaControlOrientation.RotateVector(DevicePosition);
}
}
void FDefaultXRCamera::PreRenderView_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& View)
{
check(IsInRenderingThread());
// Disable late update for day dream, their compositor doesn't support it.
// Also disable it if we are set to skip it.
const bool bDoLateUpdate = !LateUpdate.GetSkipLateUpdate_RenderThread();
if (bDoLateUpdate)
{
FQuat DeviceOrientation;
FVector DevicePosition;
if (TrackingSystem->DoesSupportLateProjectionUpdate() && TrackingSystem->GetStereoRenderingDevice())
{
View.UpdateProjectionMatrix(TrackingSystem->GetStereoRenderingDevice()->GetStereoProjectionMatrix(View.StereoViewIndex));
}
if (TrackingSystem->GetCurrentPose(DeviceId, DeviceOrientation, DevicePosition))
{
const FQuat DeltaOrient = View.BaseHmdOrientation.Inverse() * DeviceOrientation;
View.ViewRotation = FRotator(View.ViewRotation.Quaternion() * DeltaOrient);
if (bUseImplicitHMDPosition)
{
const FQuat LocalDeltaControlOrientation = View.ViewRotation.Quaternion() * DeviceOrientation.Inverse();
const FVector DeltaPosition = DevicePosition - View.BaseHmdLocation;
View.ViewLocation += LocalDeltaControlOrientation.RotateVector(DeltaPosition);
}
View.UpdateViewMatrix();
}
}
}
void FDefaultXRCamera::BeginRenderViewFamily(FSceneViewFamily& InViewFamily)
{
check(IsInGameThread());
{
// Backwards compatibility during deprecation phase. Remove once IHeadMountedDisplay::BeginRendering_GameThread has been removed.
PRAGMA_DISABLE_DEPRECATION_WARNINGS
auto HMD = TrackingSystem->GetHMDDevice();
if (HMD)
{
HMD->BeginRendering_GameThread();
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
TrackingSystem->OnBeginRendering_GameThread();
}
void FDefaultXRCamera::PreRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& ViewFamily)
{
check(IsInRenderingThread());
{
// Backwards compatibility during deprecation phase. Remove once IXRTrackingSystem::RefreshPoses has been removed.
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TrackingSystem->RefreshPoses();
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
TrackingSystem->OnBeginRendering_RenderThread(RHICmdList, ViewFamily);
{
FQuat CurrentOrientation;
FVector CurrentPosition;
if (TrackingSystem->DoesSupportLateUpdate() && TrackingSystem->GetCurrentPose(DeviceId, CurrentOrientation, CurrentPosition))
{
const FSceneView* MainView = ViewFamily.Views[0];
check(MainView);
// TODO: Should we (and do we have enough information to) double-check that the plugin actually has updated the pose here?
// ensure((CurrentPosition != MainView->BaseHmdLocation && CurrentOrientation != MainView->BaseHmdOrientation) || CurrentPosition.IsZero() || CurrentOrientation.IsIdentity() );
const FTransform OldRelativeTransform(MainView->BaseHmdOrientation, MainView->BaseHmdLocation);
const FTransform CurrentRelativeTransform(CurrentOrientation, CurrentPosition);
LateUpdate.Apply_RenderThread(ViewFamily.Scene, OldRelativeTransform, CurrentRelativeTransform);
TrackingSystem->OnLateUpdateApplied_RenderThread(RHICmdList, CurrentRelativeTransform);
{
// Backwards compatibility during deprecation phase. Remove once IHeadMountedDisplay::BeginRendering_RenderThread has been removed.
PRAGMA_DISABLE_DEPRECATION_WARNINGS
auto HMD = TrackingSystem->GetHMDDevice();
if (HMD)
{
HMD->BeginRendering_RenderThread(CurrentRelativeTransform, RHICmdList, ViewFamily);
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
}
}
}
void FDefaultXRCamera::SetupViewFamily(FSceneViewFamily& InViewFamily)
{
static const auto CVarAllowMotionBlurInVR = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("vr.AllowMotionBlurInVR"));
const bool AllowMotionBlur = (CVarAllowMotionBlurInVR && CVarAllowMotionBlurInVR->GetValueOnAnyThread() != 0);
const IHeadMountedDisplay* const HMD = TrackingSystem->GetHMDDevice();
InViewFamily.EngineShowFlags.MotionBlur = AllowMotionBlur;
InViewFamily.EngineShowFlags.HMDDistortion = HMD != nullptr ? HMD->GetHMDDistortionEnabled(InViewFamily.Scene->GetShadingPath()) : false;
InViewFamily.EngineShowFlags.StereoRendering = bCurrentFrameIsStereoRendering;
InViewFamily.EngineShowFlags.Rendering = HMD != nullptr ? !HMD->IsRenderingPaused() : true;
}
void FDefaultXRCamera::SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView)
{
FQuat DeviceOrientation;
FVector DevicePosition;
if ( TrackingSystem->GetCurrentPose(DeviceId, DeviceOrientation, DevicePosition) )
{
InView.BaseHmdOrientation = DeviceOrientation;
InView.BaseHmdLocation = DevicePosition;
}
}
bool FDefaultXRCamera::IsActiveThisFrame_Internal(const FSceneViewExtensionContext& Context) const
{
bCurrentFrameIsStereoRendering = FHMDSceneViewExtension::IsActiveThisFrame_Internal(Context); // The current context/viewport might disallow stereo rendering. Save it so we'll use the correct value in SetupViewFamily.
return bCurrentFrameIsStereoRendering && TrackingSystem->IsHeadTrackingAllowed();
}