LutBuilderHdr.shader 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. Shader "Hidden/Universal Render Pipeline/LutBuilderHdr"
  2. {
  3. HLSLINCLUDE
  4. #pragma multi_compile_local _ _TONEMAP_ACES _TONEMAP_NEUTRAL
  5. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
  6. #include "Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/Common.hlsl"
  7. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ACES.hlsl"
  8. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
  9. float4 _Lut_Params; // x: lut_height, y: 0.5 / lut_width, z: 0.5 / lut_height, w: lut_height / lut_height - 1
  10. float4 _ColorBalance; // xyz: LMS coeffs, w: unused
  11. float4 _ColorFilter; // xyz: color, w: unused
  12. float4 _ChannelMixerRed; // xyz: rgb coeffs, w: unused
  13. float4 _ChannelMixerGreen; // xyz: rgb coeffs, w: unused
  14. float4 _ChannelMixerBlue; // xyz: rgb coeffs, w: unused
  15. float4 _HueSatCon; // x: hue shift, y: saturation, z: contrast, w: unused
  16. float4 _Lift; // xyz: color, w: unused
  17. float4 _Gamma; // xyz: color, w: unused
  18. float4 _Gain; // xyz: color, w: unused
  19. float4 _Shadows; // xyz: color, w: unused
  20. float4 _Midtones; // xyz: color, w: unused
  21. float4 _Highlights; // xyz: color, w: unused
  22. float4 _ShaHiLimits; // xy: shadows min/max, zw: highlight min/max
  23. float4 _SplitShadows; // xyz: color, w: balance
  24. float4 _SplitHighlights; // xyz: color, w: unused
  25. TEXTURE2D(_CurveMaster);
  26. TEXTURE2D(_CurveRed);
  27. TEXTURE2D(_CurveGreen);
  28. TEXTURE2D(_CurveBlue);
  29. TEXTURE2D(_CurveHueVsHue);
  30. TEXTURE2D(_CurveHueVsSat);
  31. TEXTURE2D(_CurveSatVsSat);
  32. TEXTURE2D(_CurveLumVsSat);
  33. float EvaluateCurve(TEXTURE2D(curve), float t)
  34. {
  35. float x = SAMPLE_TEXTURE2D(curve, sampler_LinearClamp, float2(t, 0.0)).x;
  36. return saturate(x);
  37. }
  38. // Note: when the ACES tonemapper is selected the grading steps will be done using ACES spaces
  39. float3 ColorGrade(float3 colorLutSpace)
  40. {
  41. // Switch back to linear
  42. float3 colorLinear = LogCToLinear(colorLutSpace);
  43. // White balance in LMS space
  44. float3 colorLMS = LinearToLMS(colorLinear);
  45. colorLMS *= _ColorBalance.xyz;
  46. colorLinear = LMSToLinear(colorLMS);
  47. // Do contrast in log after white balance
  48. #if _TONEMAP_ACES
  49. float3 colorLog = ACES_to_ACEScc(unity_to_ACES(colorLinear));
  50. #else
  51. float3 colorLog = LinearToLogC(colorLinear);
  52. #endif
  53. colorLog = (colorLog - ACEScc_MIDGRAY) * _HueSatCon.z + ACEScc_MIDGRAY;
  54. #if _TONEMAP_ACES
  55. colorLinear = ACES_to_ACEScg(ACEScc_to_ACES(colorLog));
  56. #else
  57. colorLinear = LogCToLinear(colorLog);
  58. #endif
  59. // Color filter is just an unclipped multiplier
  60. colorLinear *= _ColorFilter.xyz;
  61. // Do NOT feed negative values to the following color ops
  62. colorLinear = max(0.0, colorLinear);
  63. // Split toning
  64. // As counter-intuitive as it is, to make split-toning work the same way it does in Adobe
  65. // products we have to do all the maths in gamma-space...
  66. float balance = _SplitShadows.w;
  67. float3 colorGamma = PositivePow(colorLinear, 1.0 / 2.2);
  68. float luma = saturate(GetLuminance(saturate(colorGamma)) + balance);
  69. float3 splitShadows = lerp((0.5).xxx, _SplitShadows.xyz, 1.0 - luma);
  70. float3 splitHighlights = lerp((0.5).xxx, _SplitHighlights.xyz, luma);
  71. colorGamma = SoftLight(colorGamma, splitShadows);
  72. colorGamma = SoftLight(colorGamma, splitHighlights);
  73. colorLinear = PositivePow(colorGamma, 2.2);
  74. // Channel mixing (Adobe style)
  75. colorLinear = float3(
  76. dot(colorLinear, _ChannelMixerRed.xyz),
  77. dot(colorLinear, _ChannelMixerGreen.xyz),
  78. dot(colorLinear, _ChannelMixerBlue.xyz)
  79. );
  80. // Shadows, midtones, highlights
  81. luma = GetLuminance(colorLinear);
  82. float shadowsFactor = 1.0 - smoothstep(_ShaHiLimits.x, _ShaHiLimits.y, luma);
  83. float highlightsFactor = smoothstep(_ShaHiLimits.z, _ShaHiLimits.w, luma);
  84. float midtonesFactor = 1.0 - shadowsFactor - highlightsFactor;
  85. colorLinear = colorLinear * _Shadows.xyz * shadowsFactor
  86. + colorLinear * _Midtones.xyz * midtonesFactor
  87. + colorLinear * _Highlights.xyz * highlightsFactor;
  88. // Lift, gamma, gain
  89. colorLinear = colorLinear * _Gain.xyz + _Lift.xyz;
  90. colorLinear = sign(colorLinear) * pow(abs(colorLinear), _Gamma.xyz);
  91. // HSV operations
  92. float satMult;
  93. float3 hsv = RgbToHsv(colorLinear);
  94. {
  95. // Hue Vs Sat
  96. satMult = EvaluateCurve(_CurveHueVsSat, hsv.x) * 2.0;
  97. // Sat Vs Sat
  98. satMult *= EvaluateCurve(_CurveSatVsSat, hsv.y) * 2.0;
  99. // Lum Vs Sat
  100. satMult *= EvaluateCurve(_CurveLumVsSat, Luminance(colorLinear)) * 2.0;
  101. // Hue Shift & Hue Vs Hue
  102. float hue = hsv.x + _HueSatCon.x;
  103. float offset = EvaluateCurve(_CurveHueVsHue, hue) - 0.5;
  104. hue += offset;
  105. hsv.x = RotateHue(hue, 0.0, 1.0);
  106. }
  107. colorLinear = HsvToRgb(hsv);
  108. // Global saturation
  109. luma = GetLuminance(colorLinear);
  110. colorLinear = luma.xxx + (_HueSatCon.yyy * satMult) * (colorLinear - luma.xxx);
  111. // YRGB curves
  112. // Conceptually these need to be in range [0;1] and from an artist-workflow perspective
  113. // it's easier to deal with
  114. colorLinear = FastTonemap(colorLinear);
  115. {
  116. const float kHalfPixel = (1.0 / 128.0) / 2.0;
  117. float3 c = colorLinear;
  118. // Y (master)
  119. c += kHalfPixel.xxx;
  120. float mr = EvaluateCurve(_CurveMaster, c.r);
  121. float mg = EvaluateCurve(_CurveMaster, c.g);
  122. float mb = EvaluateCurve(_CurveMaster, c.b);
  123. c = float3(mr, mg, mb);
  124. // RGB
  125. c += kHalfPixel.xxx;
  126. float r = EvaluateCurve(_CurveRed, c.r);
  127. float g = EvaluateCurve(_CurveGreen, c.g);
  128. float b = EvaluateCurve(_CurveBlue, c.b);
  129. colorLinear = float3(r, g, b);
  130. }
  131. colorLinear = FastTonemapInvert(colorLinear);
  132. colorLinear = max(0.0, colorLinear);
  133. return colorLinear;
  134. }
  135. float3 Tonemap(float3 colorLinear)
  136. {
  137. #if _TONEMAP_NEUTRAL
  138. {
  139. colorLinear = NeutralTonemap(colorLinear);
  140. }
  141. #elif _TONEMAP_ACES
  142. {
  143. // Note: input is actually ACEScg (AP1 w/ linear encoding)
  144. float3 aces = ACEScg_to_ACES(colorLinear);
  145. colorLinear = AcesTonemap(aces);
  146. }
  147. #endif
  148. return colorLinear;
  149. }
  150. float4 Frag(Varyings input) : SV_Target
  151. {
  152. // Lut space
  153. // We use Alexa LogC (El 1000) to store the LUT as it provides a good enough range
  154. // (~58.85666) and is good enough to be stored in fp16 without losing precision in the
  155. // darks
  156. float3 colorLutSpace = GetLutStripValue(input.uv, _Lut_Params);
  157. // Color grade & tonemap
  158. float3 gradedColor = ColorGrade(colorLutSpace);
  159. gradedColor = Tonemap(gradedColor);
  160. return float4(gradedColor, 1.0);
  161. }
  162. ENDHLSL
  163. SubShader
  164. {
  165. Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline"}
  166. LOD 100
  167. ZTest Always ZWrite Off Cull Off
  168. Pass
  169. {
  170. Name "LutBuilderHdr"
  171. HLSLPROGRAM
  172. #pragma vertex Vert
  173. #pragma fragment Frag
  174. ENDHLSL
  175. }
  176. }
  177. }