Files
2025-05-18 13:04:45 +08:00

265 lines
7.5 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
DiaphragmDOF/DOFCommon.usf: Common shader code for diaphragm DOF.
=============================================================================*/
#pragma once
#include "../Common.ush"
#include "../ScreenPass.ush"
// Piggy back on existing Circle DOF code.
#include "../CircleDOFCommon.ush"
//------------------------------------------------------- RECOMPILE HASH
#pragma message("UESHADERMETADATA_VERSION EADEBBCC-57EB-41E0-9606-DC289F55A057")
//------------------------------------------------------- COMPILER CONFIG
// Generate vector truncation warnings to errors.
#pragma warning(error: 3206)
// Generate error when comparing int and uint.
#pragma warning(error: 3203)
// Ignores race condition detection when writing to LDS.
#pragma warning(disable: 3584)
// Equality comparison with extraneous parentheses
#pragma dxc diagnostic ignored "-Wparentheses-equality"
//------------------------------------------------------- Readability helpers.
// Code readability improvement to make explicit compile time branches like so:
//
// if (static_condition(MyBool))
// {
// //[...]
// }
#define static_condition(test) (test)
//------------------------------------------------------- DIMENSIONS VALUES.
// Matches C++'s EDiaphragmDOFLayerProcessing
#define LAYER_PROCESSING_FOREGROUND_ONLY 0
#define LAYER_PROCESSING_FOREGROUND_HOLE_FILLING 1
#define LAYER_PROCESSING_BACKGROUND_ONLY 2
#define LAYER_PROCESSING_COMBINED 3
#define LAYER_PROCESSING_SLIGHT_OUT_OF_FOCUS 4
// Matches C++'s EDiaphragmDOFBokehSimulation
#define BOKEH_SIMULATION_DISABLED 0
#define BOKEH_SIMULATION_SIMMETRIC 1
#define BOKEH_SIMULATION_GENERAL 2
//------------------------------------------------------- ENUM VALUES
/** Different hole filling methods. */
// Hole filling technic that directly changes the foreground opacity. Simplest but hugliest.
#define HOLE_FILLING_METHOD_OPACITY_AMEND 0
// Use's foreground gathering pass.
#define HOLE_FILLING_METHOD_SEPARATE_GATHER 1
// TODO IDEA: bilateral sample foreground according to opacity.
#define HOLE_FILLING_METHOD_BILATERAL 2
/** Layout of the input of the gathering passes. */
// Scene color and CocRadius stored within RGBA buffer 0.
#define GATHER_INPUT_LAYOUT_RGB_COC 0
// Scene color and alpha stored within RGBA buffer 0, and Coc in buffer 1.
#define GATHER_INPUT_LAYOUT_RGB_ALPHA_COC 1
// Scene color within RGB_11_11_10 buffer 0, and Coc in buffer 1.
#define GATHER_INPUT_LAYOUT_RGB_SEPARATE_COC 2
//------------------------------------------------------- COMPILE TIME CONSTANTS.
// A very large Coc radius that is assumed to be unreachable, but still encodable in 16bits float.
#define EXTREMELY_LARGE_COC_RADIUS 16384
// Default border size for group.
#define DEFAULT_GROUP_BORDER_SIZE 8
// Size of the COC in pixel from full screen.
#define COC_TILE_SIZE 8
// The resolution divisor of the current pass
#define PASS_RES_DIVISOR 2
// The resolution devisor that passed as an input of the Coc flatten.
#define COC_TILE_RES_DIVISOR 2
// Number of rings on the main kernel.
#define MAIN_KERNEL_RING_COUNT 5
// Maximum abs(coc radius) the full res recombine pass is going to do.
#define MAX_RECOMBINE_ABS_COC_RADIUS 3.0
/** Width and height of the bokeh LUT. */
#define BOKEH_LUT_SIZE 32
/** Whether alpha channel should be processed or not. */
#ifdef DIM_ALPHA_CHANNEL
#define CONFIG_DOF_ALPHA (DIM_ALPHA_CHANNEL)
#else
#define CONFIG_DOF_ALPHA 0
#endif
/** Amount of error tolerated to quick fast gathering in. */
#define FAST_GATHERING_COC_ERROR 0.05
/** Whether to output a debug texture for passes. */
#define DEBUG_OUTPUT 0
//------------------------------------------------------- COMPILE TIME CONSTANTS.
// Coc radiuses are in half res.
static const float kCocRadiusToFullResFactor = 0.5;
static const int2 kSquare2x2[4] = {
int2(0, 0),
int2(1, 0),
int2(0, 1),
int2(1, 1),
};
static const int2 kOffsetsCross3x3[4] = {
int2(-1, -1),
int2( 1, -1),
int2(-1, 1),
int2( 1, 1),
};
static const int2 kOffsetsSquare3x3[9] = {
int2(-1, +1),
int2(-1, 0),
int2(-1, -1),
int2( 0, +1),
int2( 0, 0),
int2( 0, -1),
int2(+1, +1),
int2(+1, 0),
int2(+1, -1),
};
//------------------------------------------------------- PARAMETERS
// See SetCocModelParameters, CocRadiusBasis
float CocInfinityRadius;
float CocInFocusRadius;
uint bCocEnableDynamicRadiusOffset;
float CocMinRadius;
float CocMaxRadius;
float CocSqueeze;
float CocInvSqueeze;
float DepthBlurRadius;
float DepthBlurExponent;
Texture2D DynamicRadiusOffsetLUT;
SamplerState DynamicRadiusOffsetLUTSampler;
//------------------------------------------------------- DEBUG OUTPUT
#if DEBUG_OUTPUT
RWTexture2D<float4> DebugOutput;
#endif
//------------------------------------------------------- COMMON API.
#if WITH_DYNAMIC_COC_OFFSET
float GetCocOffset(float CocRadius)
{
float DynamicOffset = 0.0;
BRANCH if (bCocEnableDynamicRadiusOffset)
{
// The 1D LUT is indexed by ratio of object CoC to in-focus CoC, starting at ratio of 1 (since we only care about objects at or beyond the in-focus plane)
// and going to a maximum ratio calculated by the number of pixels in the LUT and the starting object and wall CoCs. By convention, the LUT has been
// computed with starting CoC of 32
float MaxRatio = (256 + 32) / 32;
float Ratio = CocInFocusRadius > 0 ? CocRadius / CocInFocusRadius : MaxRatio;
float2 TexCoords = float2((Ratio - 1) / (MaxRatio - 1), 0);
float Offset = DynamicRadiusOffsetLUT.SampleLevel(DynamicRadiusOffsetLUTSampler, TexCoords, 0).r * CocInFocusRadius;
DynamicOffset = -min(Offset, CocRadius);
}
return DynamicOffset;
}
#endif
// Returns the coc radius
// The unit for the output, i.e. 'encoded' pixels or physical pixels, depends on what CocRadiusBasis was used.
float SceneDepthToCocRadius(float SceneDepth)
{
const float Focus = View.DepthOfFieldFocalDistance; // TODO: rename this to DepthOfFieldFocusDistance.
// Radius from the circle of confusion.
float CocRadius = ((SceneDepth - Focus) / SceneDepth) * CocInfinityRadius;
#if WITH_DYNAMIC_COC_OFFSET
CocRadius = CocRadius + GetCocOffset(CocRadius);
#endif
// Depth blur's radius.
float DepthBlurAbsRadius = (1.0 - exp2(-SceneDepth * DepthBlurExponent)) * DepthBlurRadius;
float ReturnCoc = max(abs(CocRadius), DepthBlurAbsRadius) * sign(CocRadius);
return clamp(ReturnCoc, CocMinRadius, CocMaxRadius);
}
// Return whether this is front element from CocRadius.
bool IsForeground(float CocRadius)
{
return CocRadius < 0.0f;
}
// Faster but less accurate luma computation with a scaling by 4.
float Luma4(float3 Color)
{
return (Color.g * 2.0) + (Color.r + Color.b);
}
// Returns 1/x if x > 0, d otherwise.
float SafeRcp(float x, float d = 0.0)
{
return x > 0.0 ? rcp(x) : d;
}
// Converts a distance in full res pixel to coc distance.
#define FullResPixelDistanceToCocDistance(x) (0.5 * (x))
// Converts a distance in full res pixel to coc distance.
#define CocDistanceToFullResPixelDistance(x) (2.0 * (x))
// Utility to use a saturating affine transformation.
float SaturateWithAffineTransformation(float x, float2 AffineTransformation)
{
// Hint: Just one MAD with saturate post modifier on GCN.
return saturate(x * AffineTransformation.x + AffineTransformation.y);
}
// Affine transformtations that always return 0 or 1.
#define kContantlyPassingAffineTransformation float2(0, 1)
#define kContantlyBlockingAffineTransformation float2(0, 0)
#if 0 // TODO: COD's noise (slide 79)
#endif