239 lines
9.0 KiB
HLSL
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
|
|
}
|
|
|
|
|