ColorGradingLutPass.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. using UnityEngine.Experimental.Rendering;
  2. namespace UnityEngine.Rendering.Universal.Internal
  3. {
  4. // Note: this pass can't be done at the same time as post-processing as it needs to be done in
  5. // advance in case we're doing on-tile color grading.
  6. /// <summary>
  7. /// Renders a color grading LUT texture.
  8. /// </summary>
  9. public class ColorGradingLutPass : ScriptableRenderPass
  10. {
  11. readonly Material m_LutBuilderLdr;
  12. readonly Material m_LutBuilderHdr;
  13. readonly GraphicsFormat m_HdrLutFormat;
  14. readonly GraphicsFormat m_LdrLutFormat;
  15. RenderTargetHandle m_InternalLut;
  16. bool m_AllowColorGradingACESHDR = true;
  17. public ColorGradingLutPass(RenderPassEvent evt, PostProcessData data)
  18. {
  19. base.profilingSampler = new ProfilingSampler(nameof(ColorGradingLutPass));
  20. renderPassEvent = evt;
  21. overrideCameraTarget = true;
  22. Material Load(Shader shader)
  23. {
  24. if (shader == null)
  25. {
  26. Debug.LogError($"Missing shader. {GetType().DeclaringType.Name} render pass will not execute. Check for missing reference in the renderer resources.");
  27. return null;
  28. }
  29. return CoreUtils.CreateEngineMaterial(shader);
  30. }
  31. m_LutBuilderLdr = Load(data.shaders.lutBuilderLdrPS);
  32. m_LutBuilderHdr = Load(data.shaders.lutBuilderHdrPS);
  33. // Warm up lut format as IsFormatSupported adds GC pressure...
  34. const FormatUsage kFlags = FormatUsage.Linear | FormatUsage.Render;
  35. if (SystemInfo.IsFormatSupported(GraphicsFormat.R16G16B16A16_SFloat, kFlags))
  36. m_HdrLutFormat = GraphicsFormat.R16G16B16A16_SFloat;
  37. else if (SystemInfo.IsFormatSupported(GraphicsFormat.B10G11R11_UFloatPack32, kFlags))
  38. m_HdrLutFormat = GraphicsFormat.B10G11R11_UFloatPack32;
  39. else
  40. // Obviously using this for log lut encoding is a very bad idea for precision but we
  41. // need it for compatibility reasons and avoid black screens on platforms that don't
  42. // support floating point formats. Expect banding and posterization artifact if this
  43. // ends up being used.
  44. m_HdrLutFormat = GraphicsFormat.R8G8B8A8_UNorm;
  45. m_LdrLutFormat = GraphicsFormat.R8G8B8A8_UNorm;
  46. base.useNativeRenderPass = false;
  47. if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3 && Graphics.minOpenGLESVersion <= OpenGLESVersion.OpenGLES30 && SystemInfo.graphicsDeviceName.StartsWith("Adreno (TM) 3"))
  48. m_AllowColorGradingACESHDR = false;
  49. }
  50. public void Setup(in RenderTargetHandle internalLut)
  51. {
  52. m_InternalLut = internalLut;
  53. }
  54. /// <inheritdoc/>
  55. public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
  56. {
  57. var cmd = CommandBufferPool.Get();
  58. using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.ColorGradingLUT)))
  59. {
  60. // Fetch all color grading settings
  61. var stack = VolumeManager.instance.stack;
  62. var channelMixer = stack.GetComponent<ChannelMixer>();
  63. var colorAdjustments = stack.GetComponent<ColorAdjustments>();
  64. var curves = stack.GetComponent<ColorCurves>();
  65. var liftGammaGain = stack.GetComponent<LiftGammaGain>();
  66. var shadowsMidtonesHighlights = stack.GetComponent<ShadowsMidtonesHighlights>();
  67. var splitToning = stack.GetComponent<SplitToning>();
  68. var tonemapping = stack.GetComponent<Tonemapping>();
  69. var whiteBalance = stack.GetComponent<WhiteBalance>();
  70. ref var postProcessingData = ref renderingData.postProcessingData;
  71. bool hdr = postProcessingData.gradingMode == ColorGradingMode.HighDynamicRange;
  72. // Prepare texture & material
  73. int lutHeight = postProcessingData.lutSize;
  74. int lutWidth = lutHeight * lutHeight;
  75. var format = hdr ? m_HdrLutFormat : m_LdrLutFormat;
  76. var material = hdr ? m_LutBuilderHdr : m_LutBuilderLdr;
  77. var desc = new RenderTextureDescriptor(lutWidth, lutHeight, format, 0);
  78. desc.vrUsage = VRTextureUsage.None; // We only need one for both eyes in VR
  79. cmd.GetTemporaryRT(m_InternalLut.id, desc, FilterMode.Bilinear);
  80. // Prepare data
  81. var lmsColorBalance = ColorUtils.ColorBalanceToLMSCoeffs(whiteBalance.temperature.value, whiteBalance.tint.value);
  82. var hueSatCon = new Vector4(colorAdjustments.hueShift.value / 360f, colorAdjustments.saturation.value / 100f + 1f, colorAdjustments.contrast.value / 100f + 1f, 0f);
  83. var channelMixerR = new Vector4(channelMixer.redOutRedIn.value / 100f, channelMixer.redOutGreenIn.value / 100f, channelMixer.redOutBlueIn.value / 100f, 0f);
  84. var channelMixerG = new Vector4(channelMixer.greenOutRedIn.value / 100f, channelMixer.greenOutGreenIn.value / 100f, channelMixer.greenOutBlueIn.value / 100f, 0f);
  85. var channelMixerB = new Vector4(channelMixer.blueOutRedIn.value / 100f, channelMixer.blueOutGreenIn.value / 100f, channelMixer.blueOutBlueIn.value / 100f, 0f);
  86. var shadowsHighlightsLimits = new Vector4(
  87. shadowsMidtonesHighlights.shadowsStart.value,
  88. shadowsMidtonesHighlights.shadowsEnd.value,
  89. shadowsMidtonesHighlights.highlightsStart.value,
  90. shadowsMidtonesHighlights.highlightsEnd.value
  91. );
  92. var (shadows, midtones, highlights) = ColorUtils.PrepareShadowsMidtonesHighlights(
  93. shadowsMidtonesHighlights.shadows.value,
  94. shadowsMidtonesHighlights.midtones.value,
  95. shadowsMidtonesHighlights.highlights.value
  96. );
  97. var (lift, gamma, gain) = ColorUtils.PrepareLiftGammaGain(
  98. liftGammaGain.lift.value,
  99. liftGammaGain.gamma.value,
  100. liftGammaGain.gain.value
  101. );
  102. var (splitShadows, splitHighlights) = ColorUtils.PrepareSplitToning(
  103. splitToning.shadows.value,
  104. splitToning.highlights.value,
  105. splitToning.balance.value
  106. );
  107. var lutParameters = new Vector4(lutHeight, 0.5f / lutWidth, 0.5f / lutHeight,
  108. lutHeight / (lutHeight - 1f));
  109. // Fill in constants
  110. material.SetVector(ShaderConstants._Lut_Params, lutParameters);
  111. material.SetVector(ShaderConstants._ColorBalance, lmsColorBalance);
  112. material.SetVector(ShaderConstants._ColorFilter, colorAdjustments.colorFilter.value.linear);
  113. material.SetVector(ShaderConstants._ChannelMixerRed, channelMixerR);
  114. material.SetVector(ShaderConstants._ChannelMixerGreen, channelMixerG);
  115. material.SetVector(ShaderConstants._ChannelMixerBlue, channelMixerB);
  116. material.SetVector(ShaderConstants._HueSatCon, hueSatCon);
  117. material.SetVector(ShaderConstants._Lift, lift);
  118. material.SetVector(ShaderConstants._Gamma, gamma);
  119. material.SetVector(ShaderConstants._Gain, gain);
  120. material.SetVector(ShaderConstants._Shadows, shadows);
  121. material.SetVector(ShaderConstants._Midtones, midtones);
  122. material.SetVector(ShaderConstants._Highlights, highlights);
  123. material.SetVector(ShaderConstants._ShaHiLimits, shadowsHighlightsLimits);
  124. material.SetVector(ShaderConstants._SplitShadows, splitShadows);
  125. material.SetVector(ShaderConstants._SplitHighlights, splitHighlights);
  126. // YRGB curves
  127. material.SetTexture(ShaderConstants._CurveMaster, curves.master.value.GetTexture());
  128. material.SetTexture(ShaderConstants._CurveRed, curves.red.value.GetTexture());
  129. material.SetTexture(ShaderConstants._CurveGreen, curves.green.value.GetTexture());
  130. material.SetTexture(ShaderConstants._CurveBlue, curves.blue.value.GetTexture());
  131. // Secondary curves
  132. material.SetTexture(ShaderConstants._CurveHueVsHue, curves.hueVsHue.value.GetTexture());
  133. material.SetTexture(ShaderConstants._CurveHueVsSat, curves.hueVsSat.value.GetTexture());
  134. material.SetTexture(ShaderConstants._CurveLumVsSat, curves.lumVsSat.value.GetTexture());
  135. material.SetTexture(ShaderConstants._CurveSatVsSat, curves.satVsSat.value.GetTexture());
  136. // Tonemapping (baked into the lut for HDR)
  137. if (hdr)
  138. {
  139. material.shaderKeywords = null;
  140. switch (tonemapping.mode.value)
  141. {
  142. case TonemappingMode.Neutral: material.EnableKeyword(ShaderKeywordStrings.TonemapNeutral); break;
  143. case TonemappingMode.ACES: material.EnableKeyword(m_AllowColorGradingACESHDR ? ShaderKeywordStrings.TonemapACES : ShaderKeywordStrings.TonemapNeutral); break;
  144. default: break; // None
  145. }
  146. }
  147. renderingData.cameraData.xr.StopSinglePass(cmd);
  148. // Render the lut
  149. cmd.Blit(null, m_InternalLut.id, material);
  150. renderingData.cameraData.xr.StartSinglePass(cmd);
  151. }
  152. context.ExecuteCommandBuffer(cmd);
  153. CommandBufferPool.Release(cmd);
  154. }
  155. /// <inheritdoc/>
  156. public override void OnFinishCameraStackRendering(CommandBuffer cmd)
  157. {
  158. cmd.ReleaseTemporaryRT(m_InternalLut.id);
  159. }
  160. public void Cleanup()
  161. {
  162. CoreUtils.Destroy(m_LutBuilderLdr);
  163. CoreUtils.Destroy(m_LutBuilderHdr);
  164. }
  165. // Precomputed shader ids to same some CPU cycles (mostly affects mobile)
  166. static class ShaderConstants
  167. {
  168. public static readonly int _Lut_Params = Shader.PropertyToID("_Lut_Params");
  169. public static readonly int _ColorBalance = Shader.PropertyToID("_ColorBalance");
  170. public static readonly int _ColorFilter = Shader.PropertyToID("_ColorFilter");
  171. public static readonly int _ChannelMixerRed = Shader.PropertyToID("_ChannelMixerRed");
  172. public static readonly int _ChannelMixerGreen = Shader.PropertyToID("_ChannelMixerGreen");
  173. public static readonly int _ChannelMixerBlue = Shader.PropertyToID("_ChannelMixerBlue");
  174. public static readonly int _HueSatCon = Shader.PropertyToID("_HueSatCon");
  175. public static readonly int _Lift = Shader.PropertyToID("_Lift");
  176. public static readonly int _Gamma = Shader.PropertyToID("_Gamma");
  177. public static readonly int _Gain = Shader.PropertyToID("_Gain");
  178. public static readonly int _Shadows = Shader.PropertyToID("_Shadows");
  179. public static readonly int _Midtones = Shader.PropertyToID("_Midtones");
  180. public static readonly int _Highlights = Shader.PropertyToID("_Highlights");
  181. public static readonly int _ShaHiLimits = Shader.PropertyToID("_ShaHiLimits");
  182. public static readonly int _SplitShadows = Shader.PropertyToID("_SplitShadows");
  183. public static readonly int _SplitHighlights = Shader.PropertyToID("_SplitHighlights");
  184. public static readonly int _CurveMaster = Shader.PropertyToID("_CurveMaster");
  185. public static readonly int _CurveRed = Shader.PropertyToID("_CurveRed");
  186. public static readonly int _CurveGreen = Shader.PropertyToID("_CurveGreen");
  187. public static readonly int _CurveBlue = Shader.PropertyToID("_CurveBlue");
  188. public static readonly int _CurveHueVsHue = Shader.PropertyToID("_CurveHueVsHue");
  189. public static readonly int _CurveHueVsSat = Shader.PropertyToID("_CurveHueVsSat");
  190. public static readonly int _CurveLumVsSat = Shader.PropertyToID("_CurveLumVsSat");
  191. public static readonly int _CurveSatVsSat = Shader.PropertyToID("_CurveSatVsSat");
  192. }
  193. }
  194. }