美文网首页以废弃
UE4 自定义 FOV

UE4 自定义 FOV

作者: PanzerVor | 来源:发表于2016-09-03 14:22 被阅读912次

    FPS 游戏第一人称枪械使用统一的 fov 会产生广角畸变。这是可能需要自定义 fov。在官方的 answer hub 上找到了自定义 fov 的方法。https://answers.unrealengine.com/questions/25526/custom-mesh-fov.html

    继承自 PrimitiveComponent 的组件都有一个函数 GetRenderMatrix,返回一个从 local space 到 world space 的变换矩阵。之后还要经历 view transform 和 projection transform。

    重载这个函数,将 view transform 和自定义的 fov 的 projection transform 应用到这个变换矩阵上。最后乘上原 fov 的 view transform 和 projection transform 的逆矩阵,来抵消原 fov 的变换。

    FMatrix CustomFOVMeshComponent::GetRenderMatrix() const
    {
        //Get camera perspectiveMatrix
        APlayerController* playerController = GetWorld()->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,
                    GetWorld()->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 = GetWorld()->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();
    }
    

    相关文章

      网友评论

        本文标题:UE4 自定义 FOV

        本文链接:https://www.haomeiwen.com/subject/frwkettx.html