186 lines
6.1 KiB
HLSL
186 lines
6.1 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
PlanarReflectionShaders.usf
|
|
=============================================================================*/
|
|
|
|
#include "Common.ush"
|
|
#include "DeferredShadingCommon.ush"
|
|
#include "PlanarReflectionShared.ush"
|
|
#include "SceneTextureParameters.ush"
|
|
#include "Substrate/Substrate.ush"
|
|
|
|
Texture2D SceneColorInputTexture;
|
|
SamplerState SceneColorInputSampler;
|
|
|
|
float4 SampleSceneColorInput(float2 UV)
|
|
{
|
|
return Texture2DSampleLevel(SceneColorInputTexture, SceneColorInputSampler, UV, 0);
|
|
}
|
|
|
|
float GaussianWeight1d(float u, float KernelRadius)
|
|
{
|
|
float TwoKernelRadiusSq = 2 * KernelRadius * KernelRadius;
|
|
return exp(-u * u / TwoKernelRadiusSq) / sqrt(PI * TwoKernelRadiusSq);
|
|
}
|
|
|
|
float InvPrefilterRoughnessDistance;
|
|
|
|
void VerticalSample(float2 InUV, float y, float KernelRadiusY, float CenterDistanceToPlane, float CenterReflectionDistance, bool bSearchUp, inout float4 AccumulatedColor, inout float AccumulatedWeight)
|
|
{
|
|
float2 SampleUV = float2(InUV.x, InUV.y + y * View.BufferSizeAndInvSize.w);
|
|
float SampleDepth = CalcSceneDepth(SampleUV);
|
|
float SampleReflectionDistance = max(SampleDepth - CenterDistanceToPlane, 0);
|
|
float ScatterKernelSize = max(KernelRadiusY * saturate(SampleReflectionDistance * InvPrefilterRoughnessDistance), 1);
|
|
float SampleWeight = GaussianWeight1d(y, ScatterKernelSize);
|
|
float ColorHalfTexelOffset = .5f * View.BufferSizeAndInvSize.w;
|
|
float YPosition = InUV.y * View.BufferSizeAndInvSize.y + y;
|
|
|
|
if (bSearchUp)
|
|
{
|
|
// Mask by depth, don't accept contribution from pixels much further than the mirror reflection depth
|
|
// This prevents reading from background areas that were revealed due to the clip plane
|
|
float DepthMask = SampleReflectionDistance < CenterReflectionDistance * 2;
|
|
SampleWeight *= DepthMask;
|
|
// Can't use bilinear filtering when we are depth masking
|
|
ColorHalfTexelOffset = 0;
|
|
|
|
float ViewportMask = YPosition > View.ViewRectMin.y + 0.5;
|
|
SampleWeight *= ViewportMask;
|
|
}
|
|
else
|
|
{
|
|
float ViewportMask = YPosition < View.ViewRectMin.y + View.ViewSizeAndInvSize.y - 0.5;
|
|
SampleWeight *= ViewportMask;
|
|
}
|
|
|
|
// Half texel offset for bilinear
|
|
float4 SampleColor = SampleSceneColorInput(SampleUV + float2(0, ColorHalfTexelOffset));
|
|
|
|
// SampleColor might contain NaNs when sampling out of the view rect, and multiplying by 0 won't help
|
|
AccumulatedColor += -min(-SampleColor, 0.0) * SampleWeight;
|
|
AccumulatedWeight += SampleWeight;
|
|
}
|
|
|
|
float KernelRadiusY;
|
|
|
|
void PrefilterPlanarReflectionPS(
|
|
float2 InUV : TEXCOORD0,
|
|
float3 ScreenVector : TEXCOORD1,
|
|
float4 SVPos : SV_POSITION,
|
|
out float4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
float2 BufferUV = min(InUV, (View.ViewSizeAndInvSize.xy + View.ViewRectMin.xy - 0.5) * View.BufferSizeAndInvSize.zw);
|
|
|
|
#if ENABLE_PLANAR_REFLECTIONS_PREFILTER
|
|
BRANCH
|
|
if (KernelRadiusY > 0)
|
|
{
|
|
// Compute distance from camera origin to the camera vector intersection with the reflection plane
|
|
float CenterDistanceToPlane = -(dot(PrimaryView.TranslatedWorldCameraOrigin, PlanarReflectionStruct.ReflectionPlane.xyz) - PlanarReflectionStruct.ReflectionPlane.w) / dot(normalize(ScreenVector), PlanarReflectionStruct.ReflectionPlane.xyz);
|
|
// Note: reading from depth after the temporal AA pass
|
|
// This works without jittering because we disable temporal AA jittering for planar reflections
|
|
float CenterSceneDepth = CalcSceneDepth(BufferUV);
|
|
float CenterReflectionDistance = max(CenterSceneDepth - CenterDistanceToPlane, 0);
|
|
|
|
float4 AccumulatedColor = 0;
|
|
float AccumulatedWeight = 0;
|
|
|
|
// Two texels at a time with bilinear
|
|
{
|
|
LOOP
|
|
for (float y = 0; y < KernelRadiusY; y += 2)
|
|
{
|
|
VerticalSample(BufferUV, y, KernelRadiusY, CenterDistanceToPlane, CenterReflectionDistance, false, AccumulatedColor, AccumulatedWeight);
|
|
}
|
|
}
|
|
|
|
{
|
|
LOOP
|
|
for (float y = -2; y > -KernelRadiusY; y -= 2)
|
|
{
|
|
VerticalSample(BufferUV, y, KernelRadiusY, CenterDistanceToPlane, CenterReflectionDistance, true, AccumulatedColor, AccumulatedWeight);
|
|
}
|
|
}
|
|
|
|
AccumulatedColor = AccumulatedColor / max(AccumulatedWeight, .0001f);
|
|
|
|
// We cleared the planar reflection alpha to 1, and base pass writes 0
|
|
float ValidContentMask = 1 - AccumulatedColor.a;
|
|
OutColor = float4(AccumulatedColor.rgb, ValidContentMask);
|
|
}
|
|
else
|
|
#endif // ENABLE_PLANAR_REFLECTIONS_PREFILTER
|
|
{
|
|
float4 SceneColorValue = SampleSceneColorInput(BufferUV);
|
|
|
|
#if (ES3_1_PROFILE)
|
|
// when mesh draw command pipline is active mobile scene color contains depth in the alpha channel, any value > 1.0 has been written to.
|
|
if( SceneColorValue.a > 1.0)
|
|
{
|
|
SceneColorValue.a = 0;
|
|
}
|
|
#endif
|
|
|
|
// We cleared the planar reflection alpha to 1, and base pass writes 0
|
|
float ValidContentMask = 1 - SceneColorValue.a;
|
|
OutColor = float4(SceneColorValue.xyz, ValidContentMask);
|
|
}
|
|
}
|
|
|
|
#if SHADING_PATH_DEFERRED
|
|
|
|
void PlanarReflectionPS(
|
|
float2 BufferUV : TEXCOORD0,
|
|
float3 ScreenVector : TEXCOORD1,
|
|
float4 SVPos : SV_POSITION,
|
|
out float4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
ResolvedView = ResolveView();
|
|
OutColor = 0;
|
|
|
|
|
|
#if SUBTRATE_GBUFFER_FORMAT==1
|
|
|
|
const FSubstrateTopLayerData TopLayerData = SubstrateUnpackTopLayerData(Substrate.TopLayerTexture.Load(uint3(SVPos.xy, 0)));
|
|
|
|
float DeviceZ = SampleDeviceZFromSceneTextures(BufferUV);
|
|
float SceneDepth = ConvertFromDeviceZ(DeviceZ);
|
|
|
|
float3 TranslatedWorldPosition = ResolvedView.TranslatedWorldCameraOrigin + ScreenVector * SceneDepth;
|
|
|
|
const float Roughness = TopLayerData.Roughness;
|
|
const float3 WorldNormal = TopLayerData.WorldNormal;
|
|
const bool bNoMaterial = !IsSubstrateMaterial(TopLayerData);
|
|
|
|
// Skip unlit pixels (skybox)
|
|
BRANCH
|
|
if (!bNoMaterial)
|
|
{
|
|
OutColor = ComputePlanarReflections(TranslatedWorldPosition, WorldNormal, Roughness);
|
|
|
|
OutColor.xyz *= View.PreExposure;
|
|
}
|
|
|
|
#else
|
|
|
|
FGBufferData GBuffer = GetGBufferDataFromSceneTextures(BufferUV);
|
|
|
|
float3 TranslatedWorldPosition = GetTranslatedWorldCameraPosFromView(SVPos.xy) + ScreenVector * GBuffer.Depth;
|
|
|
|
// Skip unlit pixels (skybox)
|
|
BRANCH
|
|
if (GBuffer.ShadingModelID != SHADINGMODELID_UNLIT)
|
|
{
|
|
OutColor = ComputePlanarReflections(TranslatedWorldPosition, GBuffer.WorldNormal, GBuffer.Roughness);
|
|
|
|
OutColor.xyz *= View.PreExposure;
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif |