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

239 lines
9.0 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
DistortionAccumulatePixelShader.usf: Pixel shader for accumulating distortion offsets
=============================================================================*/
#include "Common.ush"
// Reroute distortion pass uniform buffer.
#if SHADING_PATH_MOBILE
#define MobileSceneTextures MobileDistortionPass.SceneTextures
#define DistortionParams MobileDistortionPass.DistortionParams
#define SubstrateStruct MobileDistortionPass.Substrate
#else
#define SceneTexturesStruct DistortionPass.SceneTextures
#define DistortionParams DistortionPass.DistortionParams
#define SubstrateStruct DistortionPass.Substrate
#endif
#include "SceneTexturesCommon.ush"
#include "/Engine/Generated/Material.ush"
#include "/Engine/Generated/VertexFactory.ush"
#include "DistortionCommon.ush"
#ifndef ADAPTIVE_VOLUMETRIC_SHADOW_MAP
#define ADAPTIVE_VOLUMETRIC_SHADOW_MAP 0
#endif // ADAPTIVE_VOLUMETRIC_SHADOW_MAP
#if ADAPTIVE_VOLUMETRIC_SHADOW_MAP
#define AVSM DistortionPass.AVSM
#include "HeterogeneousVolumes/HeterogeneousVolumesAdaptiveVolumetricShadowMapSampling.ush"
#endif // ADAPTIVE_VOLUMETRIC_SHADOW_MAP
// SUBSTRATE_TODO enable distortion on mobile.
#if SUBSTRATE_ENABLED && (!MATERIAL_IS_SUBSTRATE || SHADING_PATH_MOBILE)
#undef SUBSTRATE_ENABLED
#define SUBSTRATE_ENABLED 0
#endif
#if SUBSTRATE_ENABLED
#include "Substrate/SubstrateEvaluation.ush"
#endif
void ClipOccludedPixel(float PixelZ, float SceneZ)
{
#if HAS_INVERTED_Z_BUFFER
float ClipDepth = PixelZ - SceneZ;
#else
float ClipDepth = SceneZ - PixelZ;
#endif
clip(ClipDepth);
}
/** output distortion offsets as color so they can be accumulated (via blending) */
void Main(
FVertexFactoryInterpolantsVSToPS Interpolants,
float4 PixelPosition : TEXCOORD6,
in float4 SvPosition : SV_Position,
in FStereoPSInput StereoInput
OPTIONAL_IsFrontFace,
out float4 OutColor : SV_Target0
#if SUBSTRATE_ENABLED
,
out float2 OutVarianceCoverage : SV_Target1
,
out float OutClosestDepthMeter : SV_Target2
#endif
)
{
StereoSetupPS(StereoInput);
const uint EyeIndex = GetEyeIndex(StereoInput);
// material parameter inputs
FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(Interpolants, SvPosition);
FPixelMaterialInputs PixelMaterialInputs;
CalcMaterialParameters(MaterialParameters, PixelMaterialInputs, SvPosition, bIsFrontFace);
#if SHADING_PATH_MOBILE && MATERIAL_SHOULD_DISABLE_DEPTH_TEST==0
// Mobile specific:
// distortion primtitives rendered without depth testing
// discard pixels that are hidden by manually comparing them to a scene depth
float2 BufferUV = SvPositionToBufferUV(SvPosition);
ClipOccludedPixel(SvPosition.z, LookupDeviceZ(BufferUV));
#endif
// material distortion offset
half3 Normal = GetMaterialNormal(MaterialParameters, PixelMaterialInputs);
// Prevent silhouettes from geometry that is in front of distortion from being seen in the distortion
float2 NDC = (MaterialParameters.ScreenPosition.xy / MaterialParameters.ScreenPosition.w);
float2 ScreenUV = NDC * ResolvedView.ScreenPositionScaleBias.xy + ResolvedView.ScreenPositionScaleBias.wz;
FMaterialRefractionData RefractionData = GetMaterialRefraction(PixelMaterialInputs);
#if SUBSTRATE_ENABLED
FSubstrateData SubstrateData = PixelMaterialInputs.GetFrontSubstrateData();
FSubstratePixelHeader SubstratePixelHeader = MaterialParameters.GetFrontSubstrateHeader();
// Retrieve rough refraction variance
float Sigma = 0.0f;
float3 RefractionWorldNormal = MaterialParameters.CameraVector;
#if SUBSTRATE_OPTIMIZED_UNLIT
// Unlit BSDF goes through the SubstrateTree to support weighting operations. Technically, layering and mixing could also be supported.
float3 UnlitSurfaceLuminancePostCoverage = 0.0f;
float UnlitSurfaceCoverage = 0.0f;
float3 UnlitSurfaceTransmittancePreCoverage = 0.0f;
SubstratePixelHeader.SubstrateUpdateTreeUnlit(
uint2(SvPosition.xy),
MaterialParameters.CameraVector,
SubstrateData,
UnlitSurfaceLuminancePostCoverage,
UnlitSurfaceCoverage,
UnlitSurfaceTransmittancePreCoverage,
RefractionWorldNormal);
const float MaterialIOR = GetMaterialRefractionIOR(RefractionData); // Unlit does not have any surface F0 so we only use the root node input.
const bool TryToClip = true; // In this case rough refractions are not supported, we can thus always clip.
#if DISTORTION_ACCOUNT_FOR_COVERAGE
const float RefractionCoverage = UnlitSurfaceCoverage; // Coverage of the material.
#else
const float RefractionCoverage = 1.0; // Behavior where coverage is always ignored (legacy support)
#endif
const float RefractionLobeVariance = 0.0f;
OutVarianceCoverage = float2(RefractionLobeVariance, RefractionCoverage);
#else
if (SubstratePixelHeader.SubstrateTree.BSDFCount > 0)
{
const float3 V = MaterialParameters.CameraVector;
// Update tree (coverage/transmittance/luminace weights)
const FSubstrateIntegrationSettings Settings = InitSubstrateIntegrationSettings(false /*bForceFullyRough*/, false /*bRoughDiffuseEnabled*/, 0, true/*bRoughnessTracking*/);
SubstratePixelHeader.SubstrateUpdateTree(V, Settings);
RefractionWorldNormal = SubstratePixelHeader.SubstrateTree.Operators[SubstrateData.OperatorIndex].TopDownRefractionWorldNormal;
FSubstrateLobeStatistic RefractionLobeStat = SubstratePixelHeader.SubstrateTree.Operators[SubstrateData.OperatorIndex].TopDownRefractionLobeStat;
Sigma = RefractionLobeStat.Sigma;
}
// We accumulate F0 only from the top layer to evaluate the material F0 used to evaluate distortion
float3 TopF0 = 0.0f;
SUBSTRATE_UNROLL_N(SUBSTRATE_CLAMPED_CLOSURE_COUNT)
for (int BSDFIdx = 0; BSDFIdx < SubstratePixelHeader.SubstrateTree.BSDFCount; ++BSDFIdx)
{
#define BSDF SubstratePixelHeader.SubstrateTree.BSDFs[BSDFIdx]
const bool bIsVisible = SubstrateIsBSDFVisible(BSDF);
if (bIsVisible)
{
TopF0 += BSDF.TopLayerDataWeight * SubstrateGetBSDFSpecularF0(BSDF);
}
#undef BSDF
}
TopF0 = SanitizeF0(TopF0); // Sanitize, in case a Add node has been used
const float MaterialIOR = DielectricF0RGBToIor(TopF0);
const FSubstrateOperator RootOperator = SubstratePixelHeader.SubstrateTree.Operators[SubstrateData.OperatorIndex];
#if DISTORTION_ACCOUNT_FOR_COVERAGE
const float RefractionCoverage = RootOperator.Coverage; // Coverage of the material
#else
const float RefractionCoverage = 1.0; // Behavior where coverage is always ignored (legacy support)
#endif
const float RefractionLobeVariance = Sigma; // The lobe variance that can be added to in the en recover a single lobe.
// Write out variance (as this is more linear to accumulate than roughness).
OutVarianceCoverage = float2(RefractionLobeVariance, RefractionCoverage);
// Only allow clipping if roughness is close to 0.
const bool TryToClip = false; //OutVarianceCoverage.x < 0.01f; // SUBSTRATE_TODO || RefractionCoverage <= 0.0f; // Have an option to account for coverage or not?, ignored by default
#endif
const float RefractionDepthMeter = length(MaterialParameters.WorldPosition_CamRelative) * CENTIMETER_TO_METER; // Distance for camera in meters
OutClosestDepthMeter = RefractionDepthMeter;
// Compute UV distortion
float2 BufferUVDistortion = ComputeBufferUVDistortion(
MaterialParameters, PixelMaterialInputs, ResolvedView,
RefractionWorldNormal, MaterialIOR,
DistortionParams, ScreenUV, RefractionData, TryToClip, EyeIndex);
// Sample depth at distortion offset
float2 DistortBufferUV = ScreenUV + BufferUVDistortion;
#else // SUBSTRATE_ENABLED
float3 BaseColor = GetMaterialBaseColor(PixelMaterialInputs);
float Metallic = GetMaterialMetallic(PixelMaterialInputs);
float Specular = GetMaterialSpecular(PixelMaterialInputs);
float3 F0 = ComputeF0(Specular, BaseColor, Metallic);
float MaterialIOR = DielectricF0RGBToIor(F0);
// Compute UV distortion
float2 BufferUVDistortion = ComputeBufferUVDistortion(
MaterialParameters, PixelMaterialInputs, ResolvedView,
MaterialParameters.WorldNormal, MaterialIOR,
DistortionParams, ScreenUV, RefractionData, true, EyeIndex);
// Sample depth at distortion offset
float2 DistortBufferUV = ScreenUV + BufferUVDistortion;
#endif // SUBSTRATE_ENABLED
float DistortSceneDepth = CalcSceneDepth(DistortBufferUV);
// Post process UV distortion according to depth
PostProcessUVDistortion(MaterialParameters, PixelMaterialInputs, DistortSceneDepth, BufferUVDistortion, RefractionData);
// store positive and negative offsets separately
float2 PosOffset = max(BufferUVDistortion,0);
float2 NegOffset = abs(min(BufferUVDistortion,0));
// output positives in R|G channels and negatives in B|A channels
OutColor = float4(PosOffset.x,PosOffset.y,NegOffset.x,NegOffset.y);
#if ADAPTIVE_VOLUMETRIC_SHADOW_MAP
if (DistortionPass.UseAVSM)
{
float3 TranslatedWorldPosition = SvPositionToResolvedTranslatedWorld(SvPosition);
float Transmittance = saturate(AVSM_SampleTransmittance(TranslatedWorldPosition, 0));
float ApplyDistortion = (Transmittance >= DistortionPass.TransmittanceThreshold) ? 1.0 : 0.0;
OutColor *= ApplyDistortion;
}
#endif
}