UE C++ 相机视口变换(World与相机互转)
cpp
复制代码
UFUNCTION(BlueprintCallable, BlueprintPure)
static void ProjectSceneCaptureToWorld(const class USceneCaptureComponent2D* SceneCaptureComponent2D,
const FVector2D& SceneCapturePosition, FVector& WorldPosition,
FVector& WorldDirection)
{
if (!IsValid(SceneCaptureComponent2D))
{
return;
}
// 视口矩阵
const FTransform& ViewTransform = SceneCaptureComponent2D->GetComponentToWorld();
FMatrix ViewMatrix = ViewTransform.ToInverseMatrixWithScale();
ViewMatrix = ViewMatrix * FMatrix(FPlane(0, 0, 1, 0), FPlane(1, 0, 0, 0), FPlane(0, 1, 0, 0),
FPlane(0, 0, 0, 1));
const float FOV = SceneCaptureComponent2D->FOVAngle * (float)PI / 360.0f;
const FIntPoint CaptureSize(SceneCaptureComponent2D->TextureTarget->GetSurfaceWidth(),
SceneCaptureComponent2D->TextureTarget->GetSurfaceHeight());
float XAxisMultiplier;
float YAxisMultiplier;
if (CaptureSize.X > CaptureSize.Y)
{
XAxisMultiplier = 1.0f;
YAxisMultiplier = CaptureSize.X / static_cast<float>(CaptureSize.Y);
}
else
{
XAxisMultiplier = CaptureSize.Y / static_cast<float>(CaptureSize.X);
YAxisMultiplier = 1.0f;
}
// 投影矩阵
const FMatrix ProjectionMatrix = FReversedZPerspectiveMatrix(FOV, FOV, XAxisMultiplier, YAxisMultiplier,
GNearClippingPlane, GNearClippingPlane);
//视口矩阵与投影矩阵的逆矩阵
const FMatrix InverseViewMatrix = ViewMatrix.InverseFast();
const FMatrix InverseProjectionMatrix = ProjectionMatrix.Inverse();
const FIntRect ViewRect = FIntRect(0, 0, CaptureSize.X, CaptureSize.Y);
FSceneView::DeprojectScreenToWorld(SceneCapturePosition, ViewRect, InverseViewMatrix, InverseProjectionMatrix,
WorldPosition, WorldDirection);
}
cpp
复制代码
UFUNCTION(BlueprintCallable, BlueprintPure)
static bool ProjectWorldToSceneCapture(const FVector& WorldPosition,
const class USceneCaptureComponent2D* SceneCaptureComponent2D,
FVector2D& SceneCapturePosition)
{
if (!IsValid(SceneCaptureComponent2D))
{
return false;
}
//视口矩阵
const FTransform& ViewTransform = SceneCaptureComponent2D->GetComponentToWorld();
FMatrix ViewMatrix = ViewTransform.ToInverseMatrixWithScale();
ViewMatrix = ViewMatrix * FMatrix(FPlane(0, 0, 1, 0), FPlane(1, 0, 0, 0), FPlane(0, 1, 0, 0),
FPlane(0, 0, 0, 1));
const float FOV = SceneCaptureComponent2D->FOVAngle * (float)PI / 360.0f;
const FIntPoint CaptureSize(SceneCaptureComponent2D->TextureTarget->GetSurfaceWidth(),
SceneCaptureComponent2D->TextureTarget->GetSurfaceHeight());
float XAxisMultiplier;
float YAxisMultiplier;
if (CaptureSize.X > CaptureSize.Y)
{
XAxisMultiplier = 1.0f;
YAxisMultiplier = CaptureSize.X / static_cast<float>(CaptureSize.Y);
}
else
{
XAxisMultiplier = CaptureSize.Y / static_cast<float>(CaptureSize.X);
YAxisMultiplier = 1.0f;
}
// 投影矩阵
const FMatrix ProjectionMatrix = FReversedZPerspectiveMatrix(FOV, FOV, XAxisMultiplier, YAxisMultiplier,
GNearClippingPlane, GNearClippingPlane);
const FMatrix ViewProjectionMatrix = ViewMatrix * ProjectionMatrix;
const FPlane Result = ViewProjectionMatrix.TransformFVector4(FVector4(WorldPosition, 1.f));
const FIntRect viewRect = FIntRect(0, 0, CaptureSize.X, CaptureSize.Y);
if (Result.W > 0.0f)
{
// the result of this will be x and y coords in -1..1 projection space
const float RHW = 1.0f / Result.W;
const FPlane PosInScreenSpace = FPlane(Result.X * RHW, Result.Y * RHW, Result.Z * RHW, Result.W);
// Move from projection space to normalized 0..1 UI space
const float NormalizedX = (PosInScreenSpace.X / 2.f) + 0.5f;
const float NormalizedY = 1.f - (PosInScreenSpace.Y / 2.f) - 0.5f;
const FVector2D RayStartViewRectSpace(
(NormalizedX * static_cast<float>(viewRect.Width())),
(NormalizedY * static_cast<float>(viewRect.Height()))
);
SceneCapturePosition = RayStartViewRectSpace + FVector2D(static_cast<float>(viewRect.Min.X),
static_cast<float>(viewRect.Min.Y));
return true;
}
return false;
}