Files
UnrealEngine/Engine/Shaders/Private/MotionBlur/MotionBlurVelocityFlatten.usf
2025-05-18 13:04:45 +08:00

166 lines
4.9 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#define CONFIG_MAX_RANGE_SIZE DIM_BLUR_DIRECTIONS
#include "MotionBlurVelocityFlatten.ush"
#include "../LensDistortion.ush"
//------------------------------------------------------- CONSTANTS
#define TILE_SIZE (VELOCITY_FLATTEN_TILE_SIZE)
#define THREADGROUP_TOTALSIZE (TILE_SIZE * TILE_SIZE)
#ifndef CAMERA_MOTION_BLUR_MODE
// 0-off; 1-on; 2-override
#define CAMERA_MOTION_BLUR_MODE 1
#endif
//------------------------------------------------------- PARAMETERS
Texture2D<float2> DistortingDisplacementTexture;
SamplerState DistortingDisplacementSampler;
Texture2D<float2> UndistortingDisplacementTexture;
SamplerState UndistortingDisplacementSampler;
SCREEN_PASS_TEXTURE_VIEWPORT(Velocity)
float4x4 ClipToPrevClipOverride;
FScreenTransform ThreadIdToViewportUV;
FScreenTransform ViewportUVToPixelPos;
uint bCancelCameraMotion;
uint bAddCustomCameraMotion;
uint bLensDistortion;
Texture2D VelocityTexture;
Texture2D DepthTexture;
RWTexture2D<float3> OutVelocityFlatTexture;
RWTexture2DArray<float4> OutVelocityTileArray;
RWTexture2D<float4> DebugOutput;
//------------------------------------------------------- FUNCTIONS
float2 GetCameraMotionVelocity(uint2 DispatchThreadId, float Depth, float4x4 ClipToPrevClip)
{
// Compute velocity due to camera motion.
float2 ViewportUV = ((float2)DispatchThreadId.xy + 0.5) / Velocity_ViewportSize;
float2 ScreenPos = 2 * float2(ViewportUV.x, 1 - ViewportUV.y) - 1;
float4 ThisClip = float4(ScreenPos, Depth, 1);
float4 PrevClip = mul(ThisClip, ClipToPrevClip);
float2 PrevScreen = PrevClip.xy / PrevClip.w;
return AdjustClipToPrevClipForProjectionType(ScreenPos - PrevScreen, Depth);
}
float2 PreprocessVelocityForMotionBlur(uint2 DispatchThreadId, float DeviceZ, float2 Velocity, float2 CameraMotionVelocity)
{
FLATTEN
if (bCancelCameraMotion)
{
Velocity -= CameraMotionVelocity;
}
BRANCH
if (bAddCustomCameraMotion)
{
Velocity += GetCameraMotionVelocity(DispatchThreadId, DeviceZ, ClipToPrevClipOverride);
}
return Velocity;
}
//------------------------------------------------------- ENTRY POINT
[numthreads(VELOCITY_FLATTEN_TILE_SIZE, VELOCITY_FLATTEN_TILE_SIZE, 1)]
void MainCS(
uint2 GroupId : SV_GroupID,
uint2 DispatchThreadId : SV_DispatchThreadID,
uint2 GroupThreadId : SV_GroupThreadID,
uint GroupIndex : SV_GroupIndex)
{
float4 Debug = 0;
int2 OutputPixelPos = min(DispatchThreadId.xy + Velocity_ViewportMin, Velocity_ViewportMax - 1);
int2 PixelPos = OutputPixelPos;
BRANCH
if (bLensDistortion)
{
float2 DistortedViewportUV = ApplyScreenTransform(float2(DispatchThreadId), ThreadIdToViewportUV);
float2 UndistortedViewportUV = ApplyLensDistortionOnViewportUV(UndistortingDisplacementTexture, UndistortingDisplacementSampler, DistortedViewportUV);
PixelPos = int2(ApplyScreenTransform(UndistortedViewportUV, ViewportUVToPixelPos));
}
int2 DepthOffset = 0;
{
const int Cross = 1;
// For motion vector, use camera/dynamic motion from min depth pixel in pattern around pixel.
// This enables better quality outline on foreground against different motion background.
half4 Depths;
Depths.x = DepthTexture[ PixelPos + int2(-Cross, -Cross) ].x;
Depths.y = DepthTexture[ PixelPos + int2( Cross, -Cross) ].x;
Depths.z = DepthTexture[ PixelPos + int2(-Cross, Cross) ].x;
Depths.w = DepthTexture[ PixelPos + int2( Cross, Cross) ].x;
DepthOffset = Cross;
int DepthOffsetXx = Cross;
// Nearest depth is the largest depth (depth surface 0=far, 1=near).
if(Depths.x > Depths.y)
{
DepthOffsetXx = -Cross;
}
if(Depths.z > Depths.w)
{
DepthOffset.x = -Cross;
}
half DepthsXY = max(Depths.x, Depths.y);
half DepthsZW = max(Depths.z, Depths.w);
if(DepthsXY > DepthsZW)
{
DepthOffset.y = -Cross;
DepthOffset.x = DepthOffsetXx;
}
}
float4 EncodedVelocity = VelocityTexture[ PixelPos + DepthOffset ];
float DeviceZ = DepthTexture[ PixelPos + DepthOffset ].x;
float2 CameraMotionVelocity = GetCameraMotionVelocity(DispatchThreadId, DeviceZ, View.ClipToPrevClip);
float2 Velocity = CameraMotionVelocity;
FLATTEN
if (EncodedVelocity.x > 0.0)
{
Velocity = DecodeVelocityFromTexture(EncodedVelocity).xy;
}
Velocity = PreprocessVelocityForMotionBlur(DispatchThreadId, DeviceZ, Velocity, CameraMotionVelocity);
FVelocityRange VelocityPolarRange;
float2 VelocityPolar;
ReduceVelocityFlattenTile(GroupIndex, Velocity, /* out */ VelocityPolarRange, /* out */ VelocityPolar);
// Output velcity flatten texture.
{
uint2 OutputPos = select(OutputPixelPos.xy < Velocity_ViewportMax, uint2(OutputPixelPos), uint(~0).xx);
OutVelocityFlatTexture[OutputPos] = EncodeVelocityFlatten(VelocityPolar, DeviceZ);
}
// Output tile
{
uint2 OutputPos = GroupIndex == 0 ? GroupId : uint(~0).xx;
StoreVelocityRange(OutVelocityTileArray, OutputPos, PolarToCartesian(VelocityPolarRange));
}
#if DEBUG_MOTION_BLUR_OUTPUT
DebugOutput[OutputPixelPos] = Debug;
#endif
}