Files
UnrealEngine/Engine/Shaders/Private/Lumen/LumenReflectionDenoiserCommon.ush
2025-05-18 13:04:45 +08:00

98 lines
2.2 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
// Float R11G11B10 max
#define INVALID_LIGHTING float3(65024.0f, 65024.0f, 64512.0f)
bool IsLightingValid(float3 V)
{
return !all(V == INVALID_LIGHTING);
}
float3 LumenRGBToYCoCg(float3 RGB)
{
float Y = dot(RGB, float3( 1, 2, 1));
float Co = dot(RGB, float3( 2, 0, -2));
float Cg = dot(RGB, float3(-1, 2, -1));
float3 YCoCg = float3(Y, Co, Cg);
return YCoCg;
}
float3 LumenYCoCgToRGB(float3 YCoCg)
{
float Y = YCoCg.x * 0.25f;
float Co = YCoCg.y * 0.25f;
float Cg = YCoCg.z * 0.25f;
float R = Y + Co - Cg;
float G = Y + Cg;
float B = Y - Co - Cg;
float3 RGB = float3(R, G, B);
return RGB;
}
// [Moving Frostbite to Physically Based Rendering 3.0]
// Approximates factor in Lerp(N, R, factor) = dominant direction of a GGX lobe
float GetSpecularDominantDirFactor(float Roughness)
{
float S = saturate(1.0f - Roughness);
return S * (sqrt(S) + Roughness);
}
// [Moving Frostbite to Physically Based Rendering 3.0]
float GetSpecularLobeHalfAngle(float Roughness)
{
float E = 0.75f; // Percentage of preserved energy
float LobeHalfAngle = AtanFast((Pow2(Roughness) * E) / (1.0f - E));
return LobeHalfAngle;
}
float ReflectionsDenoiserOneOverTonemapRange;
float3 RGBToDenoiserSpace(float3 V)
{
if (IsLightingValid(V))
{
float Weight = 1.0f / (1.0f + Luminance(V) * ReflectionsDenoiserOneOverTonemapRange);
V = V * Weight;
}
return V;
}
float4 RGBAToDenoiserSpace(float4 V)
{
V.xyz = RGBToDenoiserSpace(V.xyz);
return V;
}
float3 DenoiserSpaceToRGB(float3 V)
{
if (IsLightingValid(V))
{
float InvWeight = 1.0f / (1.0f - Luminance(V) * ReflectionsDenoiserOneOverTonemapRange);
V = V * InvWeight;
}
return V;
}
float PackNumFramesAccumulated(float X)
{
// Assume UInt8 quantization
return X / 32.0f + 0.5f / 255.0f;
}
float UnpackNumFramesAccumulated(float X)
{
return X * 32.0f;
}
uint GetMaxFramesAccumulated(uint MaxFrames, float Roughness)
{
// Speedup accumulation for mirror reflections in order to reduce ghosting and other artifacts
// Mirror reflections don't need many samples to converge and can be mostly handled by TAA
MaxFrames = lerp(2, MaxFrames, saturate(Roughness / 0.05f));
return MaxFrames;
}