Version: Unity 6.0 (6000.0)
语言 : 中文
在 URP 中实现与 HDR 输出兼容的自定义叠加
Shader Import Settings window reference

在 URP 中使用 HDR 输出对可编程渲染通道进行故障排除

高动态范围 (HDR) 输出在应用色调映射和颜色空间转换时会更改可编程渲染通道的输入。这些更改可能导致可编程渲染通道产生不正确的结果。当使用__ HDR__高动态范围
See in Glossary
输出,且可编写脚本渲染通道在 AfterRenderingPostProcessing 注入点中或之后执行时,您需要考虑 HDR 输出所带来的变化。如果要在后期处理期间或之后添加覆盖层(例如__ UI__(即用户界面,User Interface)让用户能够与您的应用程序进行交互。Unity 目前支持三种 UI 系统。更多信息
See in Glossary
或其他摄像机的输出),同样适用此规则,因为您需要处理 HDR 输出产生的色域。要使可编程渲染通道适应 HDR 输出的变化,必须在脚本中手动执行色调映射并转换颜色空间

但是,如果在 BeforeRenderingPostProcessing 注入点处或之前添加可编程渲染通道,则无需为兼容 HDR 输出做任何更改。这是因为 Unity 在渲染 HDR 输出之前,会先执行可编写脚本渲染通道。

注意:在 Unity 执行色调映射之前,通过摄像机堆叠来渲染相机输出,可以避免此问题。之后,Unity 会对摄像机堆叠中的最后一个摄像机应用 HDR 输出处理。要了解如何设置摄像机堆叠,请参阅摄像机堆叠

在脚本中进行色调映射和颜色空间转换

为了让可编写脚本渲染通道适应 HDR 输出对颜色空间和动态范围的改变,需使用 SetupHDROutput 函数,对可编写脚本渲染通道所修改的材质进行色调映射和颜色空间转换:

  1. 打开 C# 脚本,其中包含要用于 HDR 输出的可编程渲染通道。

  2. 将名称为 SetupHDROutput 的方法添加到 Render Pass 类。

    以下脚本提供了如何使用 SetupHDROutput 函数的示例:

    class CustomFullScreenRenderPass : ScriptableRenderPass
    {
        // Leave your existing Render Pass code here
    
        static void SetupHDROutput(ref CameraData cameraData, Material material)
        {
            // This is where most HDR related code is added
        }
    }
    
  3. 添加 if 语句以检查 HDR 输出是否处于活动状态以及摄像机是否启用了后期处理。如果未满足任一条件,就禁用 HDR 输出着色器关键字以减少资源使用量。

    static void SetupHDROutput(ref CameraData cameraData, Material material)
    {
        // If post processing is enabled, color grading has already applied tone mapping
        // As a result the input here will be in the display colorspace (Rec2020, P3, etc) and in nits
        if (cameraData.isHDROutputActive && cameraData.postProcessEnabled)
        {
    
        }
        else
        {
            // If HDR output is disabled, disable HDR output-related keywords
            // If post processing is disabled, the final pass will do the color conversion so there is
            // no need to account for HDR Output
            material.DisableKeyword(HDROutputUtils.ShaderKeywords.HDR_INPUT);
        }
    }
    
  4. 按照以下方式创建变量,用于从显示器中检索并存储亮度信息。

    if (cameraData.isHDROutputActive && cameraData.postProcessEnabled)
    {
        // Get luminance information from the display, these define the dynamic range of the display.
        float minNits = cameraData.hdrDisplayInformation.minToneMapLuminance;
        float maxNits = cameraData.hdrDisplayInformation.maxToneMapLuminance;
        float paperWhite = cameraData.hdrDisplayInformation.paperWhiteNits;
    }
    else
    {
        // If HDR output is disabled, disable HDR output-related keywords
        // If post processing is disabled, the final pass will do the color conversion so there is
        // no need to account for HDR Output
        material.DisableKeyword(HDROutputUtils.ShaderKeywords.HDR_INPUT);
    }
    
  5. 从 Volume Manager 检索色调映射组件。

    if (cameraData.isHDROutputActive && cameraData.postProcessEnabled)
    {
        var tonemapping = VolumeManager.instance.stack.GetComponent<Tonemapping>();
    
        // Get luminance information from the display, these define the dynamic range of the display.
        float minNits = cameraData.hdrDisplayInformation.minToneMapLuminance;
        float maxNits = cameraData.hdrDisplayInformation.maxToneMapLuminance;
        float paperWhite = cameraData.hdrDisplayInformation.paperWhiteNits;
    }
    
  6. 添加另一个 if 语句以检查是否存在色调映射组件。如果找到色调映射组件,则可以覆盖显示器中的亮度数据。

    if (cameraData.isHDROutputActive && cameraData.postProcessEnabled)
    {
        var tonemapping = VolumeManager.instance.stack.GetComponent<Tonemapping>();
    
        // Get luminance information from the display, these define the dynamic range of the display.
        float minNits = cameraData.hdrDisplayInformation.minToneMapLuminance;
        float maxNits = cameraData.hdrDisplayInformation.maxToneMapLuminance;
        float paperWhite = cameraData.hdrDisplayInformation.paperWhiteNits;
    
        if (tonemapping != null)
        {
            // Tone mapping post process can override the luminance retrieved from the display
            if (!tonemapping.detectPaperWhite.value)
            {
                paperWhite = tonemapping.paperWhite.value;
            }
            if (!tonemapping.detectBrightnessLimits.value)
            {
                minNits = tonemapping.minNits.value;
                maxNits = tonemapping.maxNits.value;
            }
        }
    }
    
  7. 使用显示和色调映射中的亮度数据设置材质的亮度属性。

    if (cameraData.isHDROutputActive && cameraData.postProcessEnabled)
    {
        var tonemapping = VolumeManager.instance.stack.GetComponent<Tonemapping>();
    
        // Get luminance information from the display, these define the dynamic range of the display.
        float minNits = cameraData.hdrDisplayInformation.minToneMapLuminance;
        float maxNits = cameraData.hdrDisplayInformation.maxToneMapLuminance;
        float paperWhite = cameraData.hdrDisplayInformation.paperWhiteNits;
    
        if (tonemapping != null)
        {
            // Tone mapping post process can override the luminance retrieved from the display
            if (!tonemapping.detectPaperWhite.value)
            {
                paperWhite = tonemapping.paperWhite.value;
            }
            if (!tonemapping.detectBrightnessLimits.value)
            {
                minNits = tonemapping.minNits.value;
                maxNits = tonemapping.maxNits.value;
            }
        }
    
        // Pass luminance data to the material, use these to interpret the range of values the
        // input will be in.
        material.SetFloat("_MinNits", minNits);
        material.SetFloat("_MaxNits", maxNits);
        material.SetFloat("_PaperWhite", paperWhite);
    }
    
  8. 检索当前颜色空间的色域并将其传递给材质。

    // Pass luminance data to the material, use these to interpret the range of values the
    // input will be in.
    material.SetFloat("_MinNits", minNits);
    material.SetFloat("_MaxNits", maxNits);
    material.SetFloat("_PaperWhite", paperWhite);
    
    // Pass the color gamut data to the material (colorspace and transfer function).
    HDROutputUtils.GetColorSpaceForGamut(cameraData.hdrDisplayColorGamut, out int colorspaceValue);
    material.SetInteger("_HDRColorspace", colorspaceValue);
    
  9. 启用 HDR 输出着色器关键字。

    // Pass the color gamut data to the material (colorspace and transfer function).
    HDROutputUtils.GetColorSpaceForGamut(cameraData.hdrDisplayColorGamut, out int colorspaceValue);
    material.SetInteger("_HDRColorspace", colorspaceValue);
    
    // Enable HDR shader keywords
    material.EnableKeyword(HDROutputUtils.ShaderKeywords.HDR_INPUT);
    
  10. 在 Execute() 函数中调用 SetupHDROutput 方法,以确保在使用此可脚本渲染通道时,HDR 输出能得到正确处理。

完整脚本示例

以下是示例中的完整代码:

class CustomFullScreenRenderPass : ScriptableRenderPass
{
    // Leave your existing Render Pass code here

    static void SetupHDROutput(ref CameraData cameraData, Material material)
    {
        // If post processing is enabled, color grading has already applied tone mapping
        // As a result the input here will be in the display colorspace (Rec2020, P3, etc) and in nits
        if (cameraData.isHDROutputActive && cameraData.postProcessEnabled)
        {
            var tonemapping = VolumeManager.instance.stack.GetComponent<Tonemapping>();

            // Get luminance information from the display, these define the dynamic range of the display.
            float minNits = cameraData.hdrDisplayInformation.minToneMapLuminance;
            float maxNits = cameraData.hdrDisplayInformation.maxToneMapLuminance;
            float paperWhite = cameraData.hdrDisplayInformation.paperWhiteNits;

            if (tonemapping != null)
            {
                // Tone mapping post process can override the luminance retrieved from the display
                if (!tonemapping.detectPaperWhite.value)
                {
                    paperWhite = tonemapping.paperWhite.value;
                }
                if (!tonemapping.detectBrightnessLimits.value)
                {
                    minNits = tonemapping.minNits.value;
                    maxNits = tonemapping.maxNits.value;
                }
            }

            // Pass luminance data to the material, use these to interpret the range of values the
            // input will be in.
            material.SetFloat("_MinNits", minNits);
            material.SetFloat("_MaxNits", maxNits);
            material.SetFloat("_PaperWhite", paperWhite);

            // Pass the color gamut data to the material (colorspace and transfer function).
            HDROutputUtils.GetColorSpaceForGamut(cameraData.hdrDisplayColorGamut, out int colorspaceValue);
            material.SetInteger("_HDRColorspace", colorspaceValue);

            // Enable HDR shader keywords
            material.EnableKeyword(HDROutputUtils.ShaderKeywords.HDR_INPUT);
        }
        else
        {
            // If HDR output is disabled, disable HDR output-related keywords
            // If post processing is disabled, the final pass will do the color conversion so there is
            // no need to account for HDR Output
            material.DisableKeyword(HDROutputUtils.ShaderKeywords.HDR_INPUT);
        }
    }
}
在 URP 中实现与 HDR 输出兼容的自定义叠加
Shader Import Settings window reference