|
// 2023 girlfriend games |
|
|
|
|
|
#include "Player/PlatformerLocalPlayer.h" |
|
|
|
#include "SceneViewExtension.h" |
|
#include "SceneViewExtensionContext.h" |
|
#include "UI/PlatformerViewportClient.h" |
|
|
|
int32 LocalCalcLocalPlayerCachedLODDistanceFactor = 1; |
|
static FAutoConsoleVariableRef LocalCVarCalcLocalPlayerCachedLODDistanceFactor( |
|
TEXT("r.CalcLocalPlayerCachedLODDistanceFactor"), |
|
LocalCalcLocalPlayerCachedLODDistanceFactor, |
|
TEXT("Should we calculate a LOD Distance Factor based on the current FOV. Should not be necessary since LOD is already based on screen size.\n") |
|
); |
|
|
|
|
|
void CalculateProjectionMatrixGivenView(const FMinimalViewInfo& ViewInfo, TEnumAsByte<enum EAspectRatioAxisConstraint> AspectRatioAxisConstraint, FViewport* Viewport, FSceneViewProjectionData& InOutProjectionData) |
|
{ |
|
// Create the projection matrix (and possibly constrain the view rectangle) |
|
if (ViewInfo.bConstrainAspectRatio) |
|
{ |
|
FIntRect ConstrainedViewRect = Viewport->CalculateViewExtents(ViewInfo.AspectRatio, InOutProjectionData.GetViewRect()); |
|
// Enforce a particular aspect ratio for the render of the scene. |
|
// Results in black bars at top/bottom etc. |
|
/* |
|
int32 BlackBarHeight = ConstrainedViewRect.Min.Y; |
|
int32 MoveBy = BlackBarHeight / 2; |
|
|
|
ConstrainedViewRect.Min.Y -= MoveBy; |
|
ConstrainedViewRect.Max.Y -= MoveBy; |
|
*/ |
|
InOutProjectionData.SetConstrainedViewRectangle(ConstrainedViewRect); |
|
|
|
InOutProjectionData.ProjectionMatrix = ViewInfo.CalculateProjectionMatrix(); |
|
} |
|
else |
|
{ |
|
float XAxisMultiplier; |
|
float YAxisMultiplier; |
|
|
|
/* |
|
FIntRect NewViewRect = InOutProjectionData.GetViewRect(); |
|
|
|
// 4/3 -> 16/9 |
|
// 12/9 -> 16/9 |
|
|
|
// 1.333333333333333 -> 1.777777777777778 |
|
|
|
int32 ViewHeight = NewViewRect.Height(); |
|
NewViewRect.Min.Y += ViewHeight / 9; |
|
NewViewRect.Max.Y -= ViewHeight*2 / 9; |
|
|
|
InOutProjectionData.SetViewRectangle(NewViewRect);*/ |
|
|
|
const FIntRect& ViewRect = InOutProjectionData.GetViewRect(); |
|
const int32 SizeX = ViewRect.Width(); |
|
const int32 SizeY = ViewRect.Height(); |
|
|
|
AspectRatioAxisConstraint = AspectRatio_MaintainYFOV; |
|
|
|
// Aspect ratio will work like this: |
|
// 1) Check if screen width is smaller than screen height * aspect ratio |
|
// 2) if yes, work like AspectRatio_MaintainXFOV, MaintainYFOV if not |
|
// this actually will work based on the Aspect Ratio you set on your camera component! |
|
const bool bMaintainXFOV = |
|
((SizeX < (SizeY * ViewInfo.AspectRatio)) && (AspectRatioAxisConstraint == AspectRatio_MaintainYFOV || |
|
(AspectRatioAxisConstraint == AspectRatio_MaintainXFOV))) || |
|
(ViewInfo.ProjectionMode == ECameraProjectionMode::Orthographic); |
|
if (bMaintainXFOV) |
|
{ |
|
// If the viewport is wider than it is tall |
|
XAxisMultiplier = 1.0f; |
|
YAxisMultiplier = SizeX / (float)SizeY; |
|
} |
|
else |
|
{ |
|
// If the viewport is taller than it is wide |
|
XAxisMultiplier = SizeY / (float)SizeX; |
|
YAxisMultiplier = 1.0f; |
|
} |
|
|
|
float MatrixHalfFOV; |
|
if (!bMaintainXFOV && ViewInfo.AspectRatio != 0.f) |
|
{ |
|
// The view-info FOV is horizontal. But if we have a different aspect ratio constraint, we need to |
|
// adjust this FOV value using the aspect ratio it was computed with, so we that we can compute the |
|
// complementary FOV value (with the *effective* aspect ratio) correctly. |
|
const float HalfXFOV = FMath::DegreesToRadians(FMath::Max(0.001f, ViewInfo.FOV) / 2.f); |
|
const float HalfYFOV = FMath::Atan(FMath::Tan(HalfXFOV) / ViewInfo.AspectRatio); |
|
MatrixHalfFOV = HalfYFOV; |
|
} |
|
else |
|
{ |
|
// Avoid divide by zero in the projection matrix calculation by clamping FOV. |
|
// Note the division by 360 instead of 180 because we want the half-FOV. |
|
MatrixHalfFOV = FMath::Max(0.001f, ViewInfo.FOV) * (float)UE_PI / 360.0f; |
|
} |
|
|
|
if (ViewInfo.ProjectionMode == ECameraProjectionMode::Orthographic) |
|
{ |
|
const float OrthoWidth = ViewInfo.OrthoWidth / 2.0f * XAxisMultiplier; |
|
const float OrthoHeight = (ViewInfo.OrthoWidth / 2.0f) / YAxisMultiplier; |
|
|
|
const float NearPlane = ViewInfo.OrthoNearClipPlane; |
|
const float FarPlane = ViewInfo.OrthoFarClipPlane; |
|
|
|
const float ZScale = 1.0f / (FarPlane - NearPlane); |
|
const float ZOffset = -NearPlane; |
|
|
|
InOutProjectionData.ProjectionMatrix = FReversedZOrthoMatrix( |
|
OrthoWidth, |
|
OrthoHeight, |
|
ZScale, |
|
ZOffset |
|
); |
|
} |
|
else |
|
{ |
|
const float ClippingPlane = ViewInfo.GetFinalPerspectiveNearClipPlane(); |
|
InOutProjectionData.ProjectionMatrix = FReversedZPerspectiveMatrix( |
|
MatrixHalfFOV, |
|
MatrixHalfFOV, |
|
XAxisMultiplier, |
|
YAxisMultiplier, |
|
ClippingPlane, |
|
ClippingPlane |
|
); |
|
} |
|
} |
|
|
|
if (!ViewInfo.OffCenterProjectionOffset.IsZero()) |
|
{ |
|
const float Left = -1.0f + ViewInfo.OffCenterProjectionOffset.X; |
|
const float Right = Left + 2.0f; |
|
const float Bottom = -1.0f + ViewInfo.OffCenterProjectionOffset.Y; |
|
const float Top = Bottom + 2.0f; |
|
InOutProjectionData.ProjectionMatrix.M[2][0] = (Left + Right) / (Left - Right); |
|
InOutProjectionData.ProjectionMatrix.M[2][1] = (Bottom + Top) / (Bottom - Top); |
|
} |
|
} |
|
|
|
extern TAutoConsoleVariable<float> GViewportCutsceneBarOffset; |
|
|
|
bool UPlatformerLocalPlayer::GetProjectionData(FViewport* Viewport, FSceneViewProjectionData& ProjectionData, |
|
int32 StereoViewIndex) const |
|
{ |
|
|
|
if ((Viewport == nullptr) || (PlayerController == nullptr) || (Viewport->GetSizeXY().X == 0) || (Viewport->GetSizeXY().Y == 0) || (Size.X == 0) || (Size.Y == 0)) |
|
{ |
|
return false; |
|
} |
|
|
|
int32 X = FMath::TruncToInt(Origin.X * Viewport->GetSizeXY().X); |
|
int32 Y = FMath::TruncToInt(Origin.Y * Viewport->GetSizeXY().Y); |
|
|
|
X += Viewport->GetInitialPositionXY().X; |
|
Y += Viewport->GetInitialPositionXY().Y; |
|
|
|
uint32 SizeX = FMath::TruncToInt(Size.X * Viewport->GetSizeXY().X); |
|
uint32 SizeY = FMath::TruncToInt(Size.Y * Viewport->GetSizeXY().Y); |
|
|
|
|
|
FIntRect UnconstrainedRectangle = FIntRect(X, Y, X+SizeX, Y+SizeY); |
|
|
|
ProjectionData.SetViewRectangle(UnconstrainedRectangle); |
|
|
|
// Get the viewpoint. |
|
FMinimalViewInfo ViewInfo; |
|
GetViewPoint(/*out*/ ViewInfo); |
|
|
|
// If stereo rendering is enabled, update the size and offset appropriately for this pass |
|
const bool bNeedStereo = false; |
|
|
|
// scale distances for cull distance purposes by the ratio of our current FOV to the default FOV |
|
if (LocalCalcLocalPlayerCachedLODDistanceFactor != 0) |
|
{ |
|
PlayerController->LocalPlayerCachedLODDistanceFactor = ViewInfo.FOV / FMath::Max<float>(0.01f, (PlayerController->PlayerCameraManager != nullptr) ? PlayerController->PlayerCameraManager->DefaultFOV : 90.f); |
|
} |
|
else // This should be removed in the final version. Leaving in so this can be toggled on and off in order to evaluate it. |
|
{ |
|
PlayerController->LocalPlayerCachedLODDistanceFactor = 1.f; |
|
} |
|
|
|
FVector StereoViewLocation = ViewInfo.Location; |
|
|
|
// Create the view matrix |
|
ProjectionData.ViewOrigin = StereoViewLocation; |
|
ProjectionData.ViewRotationMatrix = FInverseRotationMatrix(ViewInfo.Rotation) * FMatrix( |
|
FPlane(0, 0, 1, 0), |
|
FPlane(1, 0, 0, 0), |
|
FPlane(0, 1, 0, 0), |
|
FPlane(0, 0, 0, 1)); |
|
|
|
if(auto PlatformerViewportClient = Cast<UPlatformerViewportClient>(ViewportClient.Get())) |
|
{ |
|
if(PlatformerViewportClient->CutsceneBarAlpha > 0) |
|
ViewInfo.OffCenterProjectionOffset = FVector2D(0, 2*GViewportCutsceneBarOffset.GetValueOnGameThread() * -PlatformerViewportClient->CutsceneBarAlpha); |
|
} |
|
|
|
// viewext this use case needs to be revisited |
|
if (!bNeedStereo) |
|
{ |
|
// Create the projection matrix (and possibly constrain the view rectangle) |
|
CalculateProjectionMatrixGivenView(ViewInfo, AspectRatioAxisConstraint, Viewport, /*inout*/ ProjectionData); |
|
|
|
for (auto& ViewExt : GEngine->ViewExtensions->GatherActiveExtensions(FSceneViewExtensionContext(Viewport))) |
|
{ |
|
ViewExt->SetupViewProjectionMatrix(ProjectionData); |
|
}; |
|
} |
|
|
|
return true; |
|
} |