Files
UnrealEngine/Engine/Plugins/Runtime/nDisplay/Shaders/Private/ResourceUtils.usf
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

239 lines
6.7 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "/Engine/Private/Common.ush"
#include "DisplayClusterColorCorrection.ush"
// Input texture and sampler
Texture2D InputTexture;
SamplerState InputTextureSampler;
// Definition for the color encoding and alpha overrides
// Encodings.X = Input Encoding
// Encodings.Y = Output Encoding
// Encodings.Z = Override Alpha
#define ESourceEncoding_Linear 0
#define ESourceEncoding_Gamma 1
#define ESourceEncoding_sRGB 2
#define ESourceEncoding_MediaPQ 3
#define EOverrideAlpha_None 0
#define EOverrideAlpha_Invert 1
#define EOverrideAlpha_One 2
#define EOverrideAlpha_Zero 3
// Color encoding parameters:
uint3 Encodings;
float3 DisplayGamma;
// Definition for the ColorPremultiply
// ColorPremultiply.X = Input texture Color premultiply
// ColorPremultiply.Y = Output texture Color premultiply
// ColorPremultiply.Z = SideFeather
#define EColorPremultiply_None 0
#define EColorPremultiply_Alpha 1
#define EColorPremultiply_InvertedAlpha 2
#define ESideFeather_None 0
#define ESideFeather_Linear 1
#define ESideFeather_Smooth 2
// Color modifier
uint3 ColorPremultiply;
// Feather margins
//
// Outer LT RT
// +---------------------+
// | |
// | Inner LT RT |
// | +----------+ |
// | | | |
// | +----------+ |
// | LB RB |
// +---------------------+
// LB RB
//
// L,R,T,B = Left, Right, Top, Bottom
//
// InnerFeatherMargins = <InnerL, 1-InnerR, InnerT, 1-InnerB> // Fully opaque region
// OuterFeatherMargins = <OuterL, 1-OuterR, OuterT, 1-OuterB> // Fully transparent region
float4 InnerFeatherMargins;
float4 OuterFeatherMargins;
/**
* Returns a linearly feathered alpha based on UV position and side margins.
* The feathering fades from fully transparent (Max margins) to fully opaque (Min margins).
*/
float GetSideFeatherLinear(float2 UV)
{
float2 InvUV = 1.0 - UV;
float4 uvMargins = float4(UV.x, InvUV.x, UV.y, InvUV.y);
float4 FeatherRange = InnerFeatherMargins - OuterFeatherMargins;
// Prevent division by zero by replacing 0 range with 1.0
float4 SafeFeatherRange = max(FeatherRange, 1e-5);
// Compute normalized feather
float4 NormalizedFeather = saturate((uvMargins - OuterFeatherMargins) / SafeFeatherRange);
// Small threshold for treating near-zero floats as zero, to suppress noise.
const float NearZeroThreshold = 1e-5f;
// Mask: if FeatherRange is 0, use 1.0 (i.e. fully opaque / no feather)
float4 RangeValidMask = step(NearZeroThreshold, FeatherRange);
// RangeValidMask = 0 if < 1e-5, 1 if >= 1e-5
NormalizedFeather = lerp(1.0, NormalizedFeather, RangeValidMask);
// Return combined alpha (multiplicative blend)
return NormalizedFeather.x * NormalizedFeather.y * NormalizedFeather.z * NormalizedFeather.w;
}
/**
* Computes a feathered alpha value based on side-specific margins using smoothstep transitions.
*
* Logic:
* - Inside the inner margins (`InnerFeatherMargins`): alpha = 1 (fully opaque)
* - Outside the outer margins (`OuterFeatherMargins`): alpha = 0 (fully transparent)
* - Between Min and Max: alpha fades smoothly using smoothstep
* @param UV UV coordinates (float2), expected in [0, 1] range
* @return Alpha value in [0, 1] with smooth feathering on each side
*/
float GetSideFeatherSmooth(float2 UV)
{
// Remap UVs for mirrored sides (Right and Bottom)
float2 InvUV = 1.0 - UV;
// Combine UVs into one vector: <Left, Right, Top, Bottom>
float4 uvMargins = float4(UV.x, InvUV.x, UV.y, InvUV.y);
// Compute smooth feather for all sides: Left, Right, Top, Bottom
float4 Feather = smoothstep(OuterFeatherMargins, InnerFeatherMargins, uvMargins);
// Return combined alpha (multiplicative blend)
return Feather.x * Feather.y * Feather.z * Feather.w;
}
/** Implements color encoding. */
float4 DisplayClusterEncodeColorAndAlpha(
FScreenVertexOutput Input,
float4 InColorArg)
{
float4 OutColor = InColorArg;
#if COLOR_PREMULTIPLY
// Unpremultiply color
BRANCH
if(ColorPremultiply.x == EColorPremultiply_Alpha) // Unpremultiply
{
OutColor = Unpremultiply(OutColor);
}
else if(ColorPremultiply.x == EColorPremultiply_InvertedAlpha) // Unpremultiply inverted alpha
{
OutColor = InvertedUnpremultiply(OutColor);
}
#endif
#if OVERRIDE_ALPHA
// Override alpha
BRANCH
if(Encodings.z == EOverrideAlpha_Invert)
{
OutColor.a = 1.0f - OutColor.a;
}
else if(Encodings.z == EOverrideAlpha_One)
{
OutColor.a = 1.0f;
}
else if(Encodings.z == EOverrideAlpha_Zero)
{
OutColor.a = 0.0f;
}
// Add Side Feather color
BRANCH
if(ColorPremultiply.z == ESideFeather_Linear)
{
float Feather = GetSideFeatherLinear(Input.UV.xy);
// Premultiply color and alpha
OutColor *= Feather;
}
else if(ColorPremultiply.z == ESideFeather_Smooth)
{
float Feather = GetSideFeatherSmooth(Input.UV.xy);
// Premultiply color and alpha
OutColor *= Feather;
}
#endif
#if ENCODE_INPUT || ENCODE_OUTPUT
#if ENCODE_INPUT
// Convert Input color to linear
BRANCH
if(Encodings.x == ESourceEncoding_Gamma) // Gamma -> Linear
{
OutColor.rgb = DisplayGammaCorrection(OutColor.rgb, DisplayGamma.x);
}
else if(Encodings.x == ESourceEncoding_sRGB) // sRGB -> Linear
{
OutColor.rgb = sRGBToLinear(OutColor.rgb);
}
else if(Encodings.x == ESourceEncoding_MediaPQ) // MediaPQ -> Linear
{
// Pixel shader for PQ-Linear conversion
OutColor.rgb = ST2084ToLinear(OutColor.rgb);
}
#endif // ENCODE_INPUT
#if ENCODE_OUTPUT
// Convert the output color to a output color space
BRANCH
if(Encodings.y == ESourceEncoding_Gamma) // Linear -> Gamma
{
OutColor.rgb = DisplayGammaCorrection(OutColor.rgb, DisplayGamma.y);
}
else if(Encodings.y == ESourceEncoding_sRGB) // Linear -> sRGB
{
OutColor.rgb = LinearToSrgb(OutColor.rgb);
}
else if(Encodings.y == ESourceEncoding_MediaPQ) // Linear -> MediaPQ
{
// Pixel shader for Linear-PQ conversion
float3 ColorPQ = LinearToST2084(OutColor.rgb);
OutColor.rgb = saturate(ColorPQ);
}
#endif // ENCODE_OUTPUT
#endif // ENCODE_INPUT || ENCODE_OUTPUT
#if COLOR_PREMULTIPLY
// Premultiply color
BRANCH
if(ColorPremultiply.y == EColorPremultiply_Alpha) // Premultiply
{
OutColor = Premultiply(OutColor);
}
else if(ColorPremultiply.y == EColorPremultiply_InvertedAlpha) // Premultiply inverted alpha
{
OutColor = InvertedPremultiply(OutColor);
}
#endif
return OutColor;
}
void Main(
FScreenVertexOutput Input,
out float4 OutColor : SV_Target0)
{
float4 InColor = Texture2DSample(InputTexture, InputTextureSampler, Input.UV);
OutColor = DisplayClusterEncodeColorAndAlpha(Input, InColor);
}