Files
UnrealEngine/Engine/Plugins/Compositing/LensDistortion/Shaders/Private/UVGeneration.usf
2025-05-18 13:04:45 +08:00

138 lines
4.6 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
LensDistortionUVGeneration.usf: Generate lens distortion and undistortion
UV displacement map into a render target.
The pixel shader directly compute the distort viewport UV to undistort
viewport UV displacment using Sv_Position and the reference equations and
store them into the red and green channels.
However to avoid resolving with a ferrari method, or doing a newton method
on the GPU to compute the undistort viewport UV to distort viewport UV
displacement, this couple of shaders works as follow: The vertex shader
undistort the grid's vertices, and passdown to the pixel shader the viewport
UV of where they should have been on screen without undistortion. The pixel
shader can then generate the undistort viewport UV to distort viewport UV
displacement by just subtracting the pixel's viewport UV.
=============================================================================*/
#include "/Engine/Public/Platform.ush"
// Size of the pixels in the viewport UV coordinates.
float2 PixelUVSize;
// K1, K2, K3
float3 RadialDistortionCoefs;
// P1, P2
float2 TangentialDistortionCoefs;
// Camera matrix of the undistorted viewport.
float4 UndistortedCameraMatrix;
// Camera matrix of the distorted viewport.
float4 DistortedCameraMatrix;
// Output multiply and add to the render target.
float2 OutputMultiplyAndAdd;
// Undistort a view position at V.z=1.
float2 UndistortNormalizedViewPosition(float2 V)
{
float2 V2 = V * V;
float R2 = V2.x + V2.y;
// Radial distortion (extra parenthesis to match MF_Undistortion.uasset).
float2 UndistortedV = V * (1.0 + R2 * (RadialDistortionCoefs.x + R2 * (RadialDistortionCoefs.y + R2 * RadialDistortionCoefs.z)));
// Tangential distortion.
UndistortedV.x += TangentialDistortionCoefs.y * (R2 + 2 * V2.x) + 2 * TangentialDistortionCoefs.x * V.x * V.y;
UndistortedV.y += TangentialDistortionCoefs.x * (R2 + 2 * V2.y) + 2 * TangentialDistortionCoefs.y * V.x * V.y;
return UndistortedV;
}
// Returns the undistorted viewport UV of the distorted's viewport UV.
//
// Notes:
// UVs are bottom left originated.
float2 UndistortViewportUV(float2 ViewportUV)
{
// Distorted viewport UV -> Distorted view position (z=1)
float2 DistortedViewPosition = (ViewportUV - DistortedCameraMatrix.zw) / DistortedCameraMatrix.xy;
// Compute undistorted view position (z=1)
float2 UndistortedViewPosition = UndistortNormalizedViewPosition(DistortedViewPosition);
// Undistorted view position (z=1) -> Undistorted viewport UV.
return UndistortedCameraMatrix.xy * UndistortedViewPosition + UndistortedCameraMatrix.zw;
}
// Flip UV's y component.
float2 FlipUV(float2 UV)
{
return float2(UV.x, 1 - UV.y);
}
void MainVS(
in uint GlobalVertexId : SV_VertexID,
out float2 OutVertexDistortedViewportUV : TEXCOORD0,
out float4 OutPosition : SV_POSITION
)
{
// Compute the cell index.
uint GridCellIndex = GlobalVertexId / 6;
// Compute row and column id of the cell within the grid.
uint GridColumnId = GridCellIndex / GRID_SUBDIVISION_Y;
uint GridRowId = GridCellIndex - GridColumnId * GRID_SUBDIVISION_Y;
// Compute the vertex id within a 2 triangles grid cell.
uint VertexId = GlobalVertexId - GridCellIndex * 6;
// Compute the bottom left originated UV coordinate of the triangle's vertex within the cell.
float2 CellVertexUV = float2(0x1 & ((VertexId + 1) / 3), VertexId & 0x1);
// Compute the top left originated UV of the vertex within the grid.
float2 GridInvSize = 1.f / float2(GRID_SUBDIVISION_X, GRID_SUBDIVISION_Y);
float2 GridVertexUV = FlipUV(
GridInvSize * (CellVertexUV + float2(GridColumnId, GridRowId)));
// The standard doesn't have half pixel shift.
GridVertexUV -= PixelUVSize * 0.5;
// Output vertex position.
OutPosition = float4(FlipUV(
UndistortViewportUV(GridVertexUV) + PixelUVSize * 0.5) * 2 - 1, 0, 1);
// Output top left originated UV of the vertex.
OutVertexDistortedViewportUV = GridVertexUV;
}
void MainPS(
in noperspective float2 VertexDistortedViewportUV : TEXCOORD0,
in float4 SvPosition : SV_POSITION,
out float4 OutColor : SV_Target0
)
{
// Compute the pixel's top left originated UV.
float2 ViewportUV = SvPosition.xy * PixelUVSize;
// The standard doesn't have half pixel shift.
ViewportUV -= PixelUVSize * 0.5;
float2 DistortUVtoUndistortUV = (UndistortViewportUV((ViewportUV))) - ViewportUV;
float2 UndistortUVtoDistortUV = VertexDistortedViewportUV - ViewportUV;
// Output displacement channels.
OutColor = OutputMultiplyAndAdd.y + OutputMultiplyAndAdd.x * float4(
DistortUVtoUndistortUV, UndistortUVtoDistortUV);
}