Thanks staticvoidlol for point out the issue. The last code I wrote which invoke a game thread function in render thread. The following code is my latest fix. Although it looks clumsy about calculating project/view matrix for viewport, it works perfectly here.
FMatrix CustomFOVMeshComponent::GetRenderMatrix() const
{
//Get camera perspectiveMatrix
APlayerController* playerController = ()->GetFirstPlayerController();
if (playerController)
{
ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(playerController->Player);
if (LocalPlayer != NULL && LocalPlayer->ViewportClient != NULL && LocalPlayer->ViewportClient->Viewport != NULL)
{
FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(
LocalPlayer->ViewportClient->Viewport,
()->Scene,
LocalPlayer->ViewportClient->EngineShowFlags)
.SetWorldTimes(0.0f, 0.0f, 0.0f)
.SetRealtimeUpdate(false));
FVector ViewLocation;
FRotator ViewRotation;
float MinZ = 3.0f;
float MaxZ = MinZ;
// Avoid zero ViewFOV's which cause divide by zero's in projection matrix
float MatrixFOV = FMath::Max(0.001f, WeaponFOV) * (float)PI / 360.0f;
FMatrix projMatrix = FReversedZPerspectiveMatrix(
MatrixFOV,
MatrixFOV,
1.0f,
LocalPlayer->Size.X * LocalPlayer->ViewportClient->Viewport->GetSizeXY().X / (LocalPlayer->Size.Y * LocalPlayer->ViewportClient->Viewport->GetSizeXY().Y),
MinZ,
MaxZ
);
FScaleMatrix ClipSpaceFixScale(FVector(1.0f, 1.0f, 1.0f - 0.0f));
FTranslationMatrix ClipSpaceFixTranslate(FVector(0.0f, 0.0f, 0.0f));
projMatrix = projMatrix * ClipSpaceFixScale * ClipSpaceFixTranslate;
FMatrix viewMatrix;
FMatrix invViewProjectionMatrix;
GetViewMatrices(viewMatrix, invViewProjectionMatrix);
FMatrix adjustedViewProjectMatrix = viewMatrix * projMatrix;
FMatrix inverseOldViewProjectMatrix = invViewProjectionMatrix;
FMatrix adjTransform = ComponentToWorld.ToMatrixWithScale() * adjustedViewProjectMatrix * inverseOldViewProjectMatrix;
return adjTransform;
}
else
{
return Super::GetRenderMatrix();
}
}
else
{
return Super::GetRenderMatrix();
}
}
void CustomFOVMeshComponent::GetViewMatrices(FMatrix& viewMatrix, FMatrix& invViewProjectionMatrix) const
{
APlayerController* playerController = ()->GetFirstPlayerController();
ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(playerController->Player);
//Get View Origin
FVector ViewOrigin;
FRotator ViewRotation;
playerController->GetPlayerViewPoint(/*out*/ ViewOrigin, /*out*/ ViewRotation);
FMatrix ViewRotationMatrix = FInverseRotationMatrix(ViewRotation) * FMatrix(
FPlane(0, 0, 1, 0),
FPlane(1, 0, 0, 0),
FPlane(0, 1, 0, 0),
FPlane(0, 0, 0, 1));
if (!ViewRotationMatrix.GetOrigin().IsNearlyZero(0.0f))
{
ViewOrigin += ViewRotationMatrix.InverseTransformPosition(FVector::ZeroVector);
ViewRotationMatrix = ViewRotationMatrix.RemoveTranslation();
}
// Calculate view matrix
viewMatrix = FTranslationMatrix(-ViewOrigin) * ViewRotationMatrix;
// Calculate project matrix
int32 X = FMath::TruncToInt(LocalPlayer->Origin.X * LocalPlayer->ViewportClient->Viewport->GetSizeXY().X);
int32 Y = FMath::TruncToInt(LocalPlayer->Origin.Y * LocalPlayer->ViewportClient->Viewport->GetSizeXY().Y);
uint32 SizeX = FMath::TruncToInt(LocalPlayer->Size.X * LocalPlayer->ViewportClient->Viewport->GetSizeXY().X);
uint32 SizeY = FMath::TruncToInt(LocalPlayer->Size.Y * LocalPlayer->ViewportClient->Viewport->GetSizeXY().Y);
FIntRect UnconstrainedRectangle = FIntRect(X, Y, X + SizeX, Y + SizeY);
FSceneViewProjectionData ProjectionData;
ProjectionData.SetViewRectangle(UnconstrainedRectangle);
FMinimalViewInfo OutViewInfo;
if (playerController->PlayerCameraManager != NULL)
{
OutViewInfo = playerController->PlayerCameraManager->CameraCache.POV;
OutViewInfo.FOV = playerController->PlayerCameraManager->GetFOVAngle();
playerController->GetPlayerViewPoint(/*out*/ OutViewInfo.Location, /*out*/ OutViewInfo.Rotation);
}
else
{
playerController->GetPlayerViewPoint(/*out*/ OutViewInfo.Location, /*out*/ OutViewInfo.Rotation);
}
FMinimalViewInfo::CalculateProjectionMatrixGivenView(OutViewInfo, LocalPlayer->AspectRatioAxisConstraint, LocalPlayer->ViewportClient->Viewport, /*inout*/ ProjectionData);
FMatrix ProjMatrix = ProjectionData.ProjectionMatrix;
FViewMatrices ViewMatrices;
ViewMatrices.ViewMatrix = viewMatrix;
ViewMatrices.ProjMatrix = ProjMatrix;
invViewProjectionMatrix = ViewMatrices.GetInvViewProjMatrix();
}