151 lines
5.8 KiB
HLSL
151 lines
5.8 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
DownSampleDepthPixelShader.usf: Downsamples scene depth by a factor of 2.
|
|
=============================================================================*/
|
|
|
|
#include "Common.ush"
|
|
#include "DeferredShadingCommon.ush"
|
|
#include "SceneTexturesCommon.ush"
|
|
#if NANITE_COMPOSITE
|
|
#include "Nanite/NaniteDataDecode.ush"
|
|
#endif
|
|
|
|
// This must match EDownsampleDepthFilter
|
|
#define DOWNSAMPLE_DEPTH_FILTER_POINT 0
|
|
#define DOWNSAMPLE_DEPTH_FILTER_MAX 1
|
|
#define DOWNSAMPLE_DEPTH_FILTER_CBMINMAX 2
|
|
|
|
Texture2D<uint> NaniteShadingMask;
|
|
Texture2D<float> DepthTexture;
|
|
#if OUTPUT_MINMAXDEPTH_FROM_MINMAXDEPTH
|
|
Texture2D<float2> MinMaxDepthTexture;
|
|
#endif
|
|
float2 DstToSrcPixelScale;
|
|
float2 SourceMaxUV;
|
|
float2 DestinationResolution;
|
|
uint DownsampleDepthFilter;
|
|
|
|
// Only valid when using OUTPUT_MIN_AND_MAX_DEPTH
|
|
int4 DstPixelCoordMinAndMax;
|
|
int4 SrcPixelCoordMinAndMax;
|
|
|
|
float GetDeviceZ(float2 UV)
|
|
{
|
|
return DepthTexture.Sample(GlobalPointClampedSampler, min(UV, SourceMaxUV));
|
|
}
|
|
|
|
void Main(
|
|
noperspective float4 OutUVAndScreenPos : TEXCOORD0,
|
|
in FStereoPSInput StereoInput,
|
|
in float4 SVPos : SV_POSITION,
|
|
#if OUTPUT_MIN_AND_MAX_DEPTH || OUTPUT_MINMAXDEPTH_FROM_MINMAXDEPTH
|
|
out float4 OutColor : SV_Target0
|
|
#else
|
|
out float OutDepth : SV_DEPTH
|
|
#endif
|
|
)
|
|
{
|
|
// Pixel coordinate for the output
|
|
const int2 DstPixelPos = SVPos.xy;
|
|
// Lower left corner from the input 2x2 quad
|
|
const int2 PixelPos = float2(DstPixelPos) * DstToSrcPixelScale;
|
|
|
|
#if OUTPUT_MINMAXDEPTH_FROM_MINMAXDEPTH
|
|
|
|
float2 MinMaxDepth0 = MinMaxDepthTexture.Load(uint3(clamp(PixelPos + int2(0, 0), SrcPixelCoordMinAndMax.xy, SrcPixelCoordMinAndMax.zw), 0));
|
|
float2 MinMaxDepth1 = MinMaxDepthTexture.Load(uint3(clamp(PixelPos + int2(0, 1), SrcPixelCoordMinAndMax.xy, SrcPixelCoordMinAndMax.zw), 0));
|
|
float2 MinMaxDepth2 = MinMaxDepthTexture.Load(uint3(clamp(PixelPos + int2(1, 1), SrcPixelCoordMinAndMax.xy, SrcPixelCoordMinAndMax.zw), 0));
|
|
float2 MinMaxDepth3 = MinMaxDepthTexture.Load(uint3(clamp(PixelPos + int2(1, 0), SrcPixelCoordMinAndMax.xy, SrcPixelCoordMinAndMax.zw), 0));
|
|
|
|
const float MaxDeviceZ = max(max(MinMaxDepth0.y, MinMaxDepth1.y), max(MinMaxDepth2.y, MinMaxDepth3.y));
|
|
const float MinDeviceZ = min(min(MinMaxDepth0.x, MinMaxDepth1.x), min(MinMaxDepth2.x, MinMaxDepth3.x));
|
|
OutColor = float4(MinDeviceZ, MaxDeviceZ, 0.0f, 0.0f);
|
|
|
|
#else // OUTPUT_MINMAXDEPTH_FROM_MINMAXDEPTH
|
|
|
|
float DeviceZ0 = DepthTexture.Load(uint3(clamp(PixelPos + int2(0, 0), SrcPixelCoordMinAndMax.xy, SrcPixelCoordMinAndMax.zw), 0));
|
|
float DeviceZ1 = DepthTexture.Load(uint3(clamp(PixelPos + int2(0, 1), SrcPixelCoordMinAndMax.xy, SrcPixelCoordMinAndMax.zw), 0));
|
|
float DeviceZ2 = DepthTexture.Load(uint3(clamp(PixelPos + int2(1, 1), SrcPixelCoordMinAndMax.xy, SrcPixelCoordMinAndMax.zw), 0));
|
|
float DeviceZ3 = DepthTexture.Load(uint3(clamp(PixelPos + int2(1, 0), SrcPixelCoordMinAndMax.xy, SrcPixelCoordMinAndMax.zw), 0));
|
|
|
|
#if OUTPUT_MIN_AND_MAX_DEPTH
|
|
|
|
const float MaxDeviceZ = max(max(DeviceZ0, DeviceZ1), max(DeviceZ2, DeviceZ3));
|
|
const float MinDeviceZ = min(min(DeviceZ0, DeviceZ1), min(DeviceZ2, DeviceZ3));
|
|
OutColor = float4(MinDeviceZ, MaxDeviceZ, 0.0f, 0.0f);
|
|
|
|
#else // OUTPUT_MIN_AND_MAX_DEPTH
|
|
|
|
float Depth = 0;
|
|
|
|
if (DownsampleDepthFilter < DOWNSAMPLE_DEPTH_FILTER_CBMINMAX)
|
|
{
|
|
#if HAS_INVERTED_Z_BUFFER
|
|
float FarDepth = min(min(DeviceZ0, DeviceZ1), min(DeviceZ2, DeviceZ3));
|
|
#else
|
|
float FarDepth = max(max(DeviceZ0, DeviceZ1), max(DeviceZ2, DeviceZ3));
|
|
#endif
|
|
|
|
// Max depth shrinks the silhouettes around foreground objects and is conservative for depth testing
|
|
// Sample 0 has consistent error, use whichever one is requested for this downsample
|
|
Depth = DownsampleDepthFilter == DOWNSAMPLE_DEPTH_FILTER_MAX ? FarDepth : DeviceZ0;
|
|
}
|
|
else // DownsampleDepthFilter == DOWNSAMPLE_DEPTH_FILTER_CBMINMAX
|
|
{
|
|
const float MaxDeviceZ = max(max(DeviceZ0, DeviceZ1), max(DeviceZ2, DeviceZ3));
|
|
const float MinDeviceZ = min(min(DeviceZ0, DeviceZ1), min(DeviceZ2, DeviceZ3));
|
|
|
|
const uint2 PixelPosStep = (DstPixelPos >> 1) * 2;
|
|
uint CheckerBoard = (DstPixelPos.x - PixelPosStep.x); // horizontal alternance of black and white
|
|
CheckerBoard = (DstPixelPos.y - PixelPosStep.y) == 0 ? CheckerBoard : 1 - CheckerBoard;// vertical toggle of horizontal checker on odd lines
|
|
|
|
Depth = CheckerBoard > 0 ? MaxDeviceZ : MinDeviceZ;
|
|
}
|
|
|
|
OutDepth = Depth;
|
|
|
|
#endif // OUTPUT_MIN_AND_MAX_DEPTH
|
|
|
|
#endif // OUTPUT_MINMAXDEPTH_FROM_MINMAXDEPTH
|
|
}
|
|
|
|
#ifndef STENCIL_LIGHTING_CHANNELS_SHIFT
|
|
#define STENCIL_LIGHTING_CHANNELS_SHIFT 0
|
|
#endif
|
|
|
|
// Must match C++
|
|
#define STENCIL_DISTANCE_FIELD_REPRESENTATION_BIT_ID 2
|
|
|
|
void CopyStencilToLightingChannelsPS(
|
|
noperspective float4 InUV : TEXCOORD0,
|
|
in FStereoPSInput StereoInput,
|
|
out uint4 OutValue : SV_Target0
|
|
)
|
|
{
|
|
uint2 IntUV = (uint2)((float2)InUV.xy * (float2)View.BufferSizeAndInvSize.xy);
|
|
|
|
uint LightingChannels = 0;
|
|
uint HasDistanceFieldRepresentationMask = 0;
|
|
|
|
#if NANITE_COMPOSITE
|
|
FShadingMask UnpackedMask = UnpackShadingMask(NaniteShadingMask.Load(uint3(IntUV, 0)));
|
|
BRANCH
|
|
if (UnpackedMask.bIsNanitePixel)
|
|
{
|
|
LightingChannels = UnpackedMask.LightingChannels;
|
|
HasDistanceFieldRepresentationMask = (select(UnpackedMask.bHasDistanceField, 1u, 0u) << LIGHTING_CHANNELS_TEXTURE_DISTANCE_FIELD_REPRESENTATION_BIT);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
const uint Stencil = SceneStencilTexture.Load(uint3(IntUV, 0)) STENCIL_COMPONENT_SWIZZLE;
|
|
const uint ShiftedStencil = Stencil >> STENCIL_LIGHTING_CHANNELS_SHIFT;
|
|
// Flip the lowest channel bit, it was stored inverted so we can clear stencil to 0 as a default
|
|
LightingChannels = (ShiftedStencil & 0x6) | (~ShiftedStencil & 0x1);
|
|
HasDistanceFieldRepresentationMask = ((Stencil >> STENCIL_DISTANCE_FIELD_REPRESENTATION_BIT_ID) & 0x1) << LIGHTING_CHANNELS_TEXTURE_DISTANCE_FIELD_REPRESENTATION_BIT;
|
|
}
|
|
|
|
OutValue = LightingChannels | HasDistanceFieldRepresentationMask;
|
|
}
|