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

149 lines
5.9 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Common.ush"
#include "SceneTexturesCommon.ush"
void DownsampleLightShaftsVertexMain(
in float2 InPosition : ATTRIBUTE0,
in float2 InUV : ATTRIBUTE1,
out float2 OutTexCoord : TEXCOORD0,
out float3 OutScreenVector : TEXCOORD1,
out float4 OutPosition : SV_POSITION
)
{
DrawRectangle(float4(InPosition.xy, 0, 1), InUV, OutPosition, OutTexCoord);
OutScreenVector = ScreenVectorFromScreenRect(float4(OutPosition.xy, 1, 0));
}
/** Origin in texture coordinates in xy. */
float2 TextureSpaceBlurOrigin;
float BloomMaxBrightness;
/** Mins in xy, Maxes in zw. */
float4 UVMinMax;
float4 AspectRatioAndInvAspectRatio;
/** 1.0f / OcclusionDepthRange in x, BloomScale in y, 1 in z, OcclusionMaskDarkness in w. */
float4 LightShaftParameters;
/** Tint in rgb, threshold in a. */
float4 BloomTintAndThreshold;
/** Result of the previous pass, rgb contains bloom color and a contains an occlusion mask. */
Texture2D SourceTexture;
#define SourceTextureSampler GlobalBilinearClampedSampler
void DownsampleLightShaftsPixelMain(
float2 InUV : TEXCOORD0,
float3 ScreenVector : TEXCOORD1,
out float4 OutColor : SV_Target0)
{
OutColor = 1;
#if OCCLUSION_TERM
float SceneDepth = CalcSceneDepth(InUV);
float2 NormalizedCoordinates = (InUV - UVMinMax.xy) / UVMinMax.zw;
// Setup a mask that is 1 at the edges of the screen and 0 at the center
float EdgeMask = 1.0f - NormalizedCoordinates.x * (1.0f - NormalizedCoordinates.x) * NormalizedCoordinates.y * (1.0f - NormalizedCoordinates.y) * 8.0f;
EdgeMask = EdgeMask * EdgeMask * EdgeMask * EdgeMask;
float InvOcclusionDepthRange = LightShaftParameters.x;
// Filter the occlusion mask instead of the depths
float OcclusionMask = saturate(SceneDepth * InvOcclusionDepthRange);
// Apply the edge mask to the occlusion factor
OutColor.x = max(OcclusionMask, EdgeMask);
#else
float3 SceneColor = CalcSceneColor(InUV);
float SceneDepth = CalcSceneDepth(InUV);
float2 NormalizedCoordinates = (InUV - UVMinMax.xy) / UVMinMax.zw;
// Setup a mask that is 1 at the edges of the screen and 0 at the center
float EdgeMask = 1.0f - NormalizedCoordinates.x * (1.0f - NormalizedCoordinates.x) * NormalizedCoordinates.y * (1.0f - NormalizedCoordinates.y) * 8.0f;
EdgeMask = EdgeMask * EdgeMask * EdgeMask * EdgeMask;
// Only bloom colors according if post exposure brightness is over BloomThreshold,
// and if brightness is greater than BloomMaxBrightness, scale it down to BloomMaxBrightness to avoid saturated artefacts.
float Luminance = max(dot(SceneColor, half3(.3f, .59f, .11f)), 6.10352e-5);
float AdjustedLuminance = clamp(Luminance - BloomTintAndThreshold.a, 0.0f, BloomMaxBrightness);
float3 BloomColor = LightShaftParameters.y * SceneColor / Luminance * AdjustedLuminance * 2.0f;
float InvOcclusionDepthRange = LightShaftParameters.x;
// Only allow bloom from pixels whose depth are in the far half of OcclusionDepthRange
float BloomDistanceMask = saturate((SceneDepth - .5f / InvOcclusionDepthRange) * InvOcclusionDepthRange);
// Setup a mask that is 0 at TextureSpaceBlurOrigin and increases to 1 over distance
float BlurOriginDistanceMask = 1.0f - saturate(length(TextureSpaceBlurOrigin.xy - InUV * AspectRatioAndInvAspectRatio.zw) * 2.0f);
// Calculate bloom color with masks applied
OutColor.rgb = BloomColor * BloomTintAndThreshold.rgb * BloomDistanceMask * (1.0f - EdgeMask) * BlurOriginDistanceMask * BlurOriginDistanceMask;
#endif
}
float4 RadialBlurParameters;
#ifndef NUM_SAMPLES
#define NUM_SAMPLES 1
#endif
void BlurLightShaftsMain(
noperspective float4 UVAndScreenPos : TEXCOORD0,
out float4 OutColor : SV_Target0)
{
float2 UV = UVAndScreenPos.xy;
float3 BlurredValues = 0;
// Scale the UVs so that the blur will be the same pixel distance in x and y
float2 AspectCorrectedUV = UV * AspectRatioAndInvAspectRatio.zw;
// Increase the blur distance exponentially in each pass
float PassScale = pow(.4f * NUM_SAMPLES, RadialBlurParameters.z);
float2 AspectCorrectedBlurVector = (TextureSpaceBlurOrigin.xy - AspectCorrectedUV)
// Prevent reading past the light position
* min(RadialBlurParameters.y * PassScale, 1);
float2 BlurVector = AspectCorrectedBlurVector * AspectRatioAndInvAspectRatio.xy;
UNROLL
for (int SampleIndex = 0; SampleIndex < NUM_SAMPLES; SampleIndex++)
{
float2 SampleUVs = (AspectCorrectedUV + AspectCorrectedBlurVector * SampleIndex / (float)NUM_SAMPLES) * AspectRatioAndInvAspectRatio.xy;
// Needed because sometimes the source texture is larger than the part we are reading from
float2 ClampedUVs = clamp(SampleUVs, UVMinMax.xy, UVMinMax.zw);
float3 SampleValue = Texture2DSample(SourceTexture, SourceTextureSampler, ClampedUVs).xyz;
BlurredValues += SampleValue;
}
OutColor.rgb = BlurredValues / (float)NUM_SAMPLES;
OutColor.a = 1;
}
void FinishOcclusionMain(
noperspective float4 UVAndScreenPos : TEXCOORD0,
out float4 OutColor : SV_Target0)
{
float2 UV = UVAndScreenPos.xy;
float LightShaftOcclusion = Texture2DSample(SourceTexture, SourceTextureSampler, UV).x;
// LightShaftParameters.w is OcclusionMaskDarkness, use that to control what an occlusion value of 0 maps to
float FinalOcclusion = lerp(LightShaftParameters.w, 1, LightShaftOcclusion * LightShaftOcclusion);
// Setup a mask based on where the blur origin is
float BlurOriginDistanceMask = saturate(length(TextureSpaceBlurOrigin.xy - UV * AspectRatioAndInvAspectRatio.zw) * .2f);
// Fade out occlusion over distance away from the blur origin
FinalOcclusion = lerp(FinalOcclusion, 1, BlurOriginDistanceMask);
OutColor = float4(FinalOcclusion, 1, 1, 1);
}
void ApplyLightShaftsPixelMain(
noperspective float4 UVAndScreenPos : TEXCOORD0,
out float4 OutColor : SV_Target0)
{
float2 UV = UVAndScreenPos.xy;
float4 LightShaftColorAndMask = Texture2DSample(SourceTexture, SourceTextureSampler, clamp(UV, UVMinMax.xy, UVMinMax.zw));
OutColor = RETURN_COLOR(float4(LightShaftColorAndMask.rgb, 1));
}