123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- Shader "Hidden/Universal Render Pipeline/LutBuilderHdr"
- {
- HLSLINCLUDE
- #pragma multi_compile_local _ _TONEMAP_ACES _TONEMAP_NEUTRAL
-
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
- #include "Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/Common.hlsl"
- #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl"
- #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
- float4 _Lut_Params; // x: lut_height, y: 0.5 / lut_width, z: 0.5 / lut_height, w: lut_height / lut_height - 1
- float4 _ColorBalance; // xyz: LMS coeffs, w: unused
- float4 _ColorFilter; // xyz: color, w: unused
- float4 _ChannelMixerRed; // xyz: rgb coeffs, w: unused
- float4 _ChannelMixerGreen; // xyz: rgb coeffs, w: unused
- float4 _ChannelMixerBlue; // xyz: rgb coeffs, w: unused
- float4 _HueSatCon; // x: hue shift, y: saturation, z: contrast, w: unused
- float4 _Lift; // xyz: color, w: unused
- float4 _Gamma; // xyz: color, w: unused
- float4 _Gain; // xyz: color, w: unused
- float4 _Shadows; // xyz: color, w: unused
- float4 _Midtones; // xyz: color, w: unused
- float4 _Highlights; // xyz: color, w: unused
- float4 _ShaHiLimits; // xy: shadows min/max, zw: highlight min/max
- float4 _SplitShadows; // xyz: color, w: balance
- float4 _SplitHighlights; // xyz: color, w: unused
- TEXTURE2D(_CurveMaster);
- TEXTURE2D(_CurveRed);
- TEXTURE2D(_CurveGreen);
- TEXTURE2D(_CurveBlue);
- TEXTURE2D(_CurveHueVsHue);
- TEXTURE2D(_CurveHueVsSat);
- TEXTURE2D(_CurveSatVsSat);
- TEXTURE2D(_CurveLumVsSat);
- float EvaluateCurve(TEXTURE2D(curve), float t)
- {
- float x = SAMPLE_TEXTURE2D(curve, sampler_LinearClamp, float2(t, 0.0)).x;
- return saturate(x);
- }
- // Note: when the ACES tonemapper is selected the grading steps will be done using ACES spaces
- float3 ColorGrade(float3 colorLutSpace)
- {
- // Switch back to linear
- float3 colorLinear = LogCToLinear(colorLutSpace);
- // White balance in LMS space
- float3 colorLMS = LinearToLMS(colorLinear);
- colorLMS *= _ColorBalance.xyz;
- colorLinear = LMSToLinear(colorLMS);
- // Do contrast in log after white balance
- #if _TONEMAP_ACES
- float3 colorLog = ACES_to_ACEScc(unity_to_ACES(colorLinear));
- #else
- float3 colorLog = LinearToLogC(colorLinear);
- #endif
- colorLog = (colorLog - ACEScc_MIDGRAY) * _HueSatCon.z + ACEScc_MIDGRAY;
-
- #if _TONEMAP_ACES
- colorLinear = ACES_to_ACEScg(ACEScc_to_ACES(colorLog));
- #else
- colorLinear = LogCToLinear(colorLog);
- #endif
- // Color filter is just an unclipped multiplier
- colorLinear *= _ColorFilter.xyz;
- // Do NOT feed negative values to the following color ops
- colorLinear = max(0.0, colorLinear);
- // Split toning
- // As counter-intuitive as it is, to make split-toning work the same way it does in Adobe
- // products we have to do all the maths in gamma-space...
- float balance = _SplitShadows.w;
- float3 colorGamma = PositivePow(colorLinear, 1.0 / 2.2);
- float luma = saturate(GetLuminance(saturate(colorGamma)) + balance);
- float3 splitShadows = lerp((0.5).xxx, _SplitShadows.xyz, 1.0 - luma);
- float3 splitHighlights = lerp((0.5).xxx, _SplitHighlights.xyz, luma);
- colorGamma = SoftLight(colorGamma, splitShadows);
- colorGamma = SoftLight(colorGamma, splitHighlights);
- colorLinear = PositivePow(colorGamma, 2.2);
- // Channel mixing (Adobe style)
- colorLinear = float3(
- dot(colorLinear, _ChannelMixerRed.xyz),
- dot(colorLinear, _ChannelMixerGreen.xyz),
- dot(colorLinear, _ChannelMixerBlue.xyz)
- );
- // Shadows, midtones, highlights
- luma = GetLuminance(colorLinear);
- float shadowsFactor = 1.0 - smoothstep(_ShaHiLimits.x, _ShaHiLimits.y, luma);
- float highlightsFactor = smoothstep(_ShaHiLimits.z, _ShaHiLimits.w, luma);
- float midtonesFactor = 1.0 - shadowsFactor - highlightsFactor;
- colorLinear = colorLinear * _Shadows.xyz * shadowsFactor
- + colorLinear * _Midtones.xyz * midtonesFactor
- + colorLinear * _Highlights.xyz * highlightsFactor;
- // Lift, gamma, gain
- colorLinear = colorLinear * _Gain.xyz + _Lift.xyz;
- colorLinear = sign(colorLinear) * pow(abs(colorLinear), _Gamma.xyz);
- // HSV operations
- float satMult;
- float3 hsv = RgbToHsv(colorLinear);
- {
- // Hue Vs Sat
- satMult = EvaluateCurve(_CurveHueVsSat, hsv.x) * 2.0;
- // Sat Vs Sat
- satMult *= EvaluateCurve(_CurveSatVsSat, hsv.y) * 2.0;
- // Lum Vs Sat
- satMult *= EvaluateCurve(_CurveLumVsSat, Luminance(colorLinear)) * 2.0;
- // Hue Shift & Hue Vs Hue
- float hue = hsv.x + _HueSatCon.x;
- float offset = EvaluateCurve(_CurveHueVsHue, hue) - 0.5;
- hue += offset;
- hsv.x = RotateHue(hue, 0.0, 1.0);
- }
- colorLinear = HsvToRgb(hsv);
- // Global saturation
- luma = GetLuminance(colorLinear);
- colorLinear = luma.xxx + (_HueSatCon.yyy * satMult) * (colorLinear - luma.xxx);
- // YRGB curves
- // Conceptually these need to be in range [0;1] and from an artist-workflow perspective
- // it's easier to deal with
- colorLinear = FastTonemap(colorLinear);
- {
- const float kHalfPixel = (1.0 / 128.0) / 2.0;
- float3 c = colorLinear;
- // Y (master)
- c += kHalfPixel.xxx;
- float mr = EvaluateCurve(_CurveMaster, c.r);
- float mg = EvaluateCurve(_CurveMaster, c.g);
- float mb = EvaluateCurve(_CurveMaster, c.b);
- c = float3(mr, mg, mb);
- // RGB
- c += kHalfPixel.xxx;
- float r = EvaluateCurve(_CurveRed, c.r);
- float g = EvaluateCurve(_CurveGreen, c.g);
- float b = EvaluateCurve(_CurveBlue, c.b);
- colorLinear = float3(r, g, b);
- }
- colorLinear = FastTonemapInvert(colorLinear);
- colorLinear = max(0.0, colorLinear);
- return colorLinear;
- }
- float3 Tonemap(float3 colorLinear)
- {
- #if _TONEMAP_NEUTRAL
- {
- colorLinear = NeutralTonemap(colorLinear);
- }
- #elif _TONEMAP_ACES
- {
- // Note: input is actually ACEScg (AP1 w/ linear encoding)
- float3 aces = ACEScg_to_ACES(colorLinear);
- colorLinear = AcesTonemap(aces);
- }
- #endif
- return colorLinear;
- }
- float4 Frag(Varyings input) : SV_Target
- {
- // Lut space
- // We use Alexa LogC (El 1000) to store the LUT as it provides a good enough range
- // (~58.85666) and is good enough to be stored in fp16 without losing precision in the
- // darks
- float3 colorLutSpace = GetLutStripValue(input.uv, _Lut_Params);
- // Color grade & tonemap
- float3 gradedColor = ColorGrade(colorLutSpace);
- gradedColor = Tonemap(gradedColor);
- return float4(gradedColor, 1.0);
- }
- ENDHLSL
- SubShader
- {
- Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline"}
- LOD 100
- ZTest Always ZWrite Off Cull Off
- Pass
- {
- Name "LutBuilderHdr"
- HLSLPROGRAM
- #pragma vertex Vert
- #pragma fragment Frag
- ENDHLSL
- }
- }
- }
|