版本:Unity 6 (6000.0)
语言:英语
在 URP 中实现兼容 HDR 输出的自定义叠加
图形性能和分析

URP 中使用 HDR 输出的 Scriptable Render Pass 疑难解答

高动态范围 (HDR) 输出在应用色调映射和色彩空间转换时会更改 Scriptable Render Pass 的输入。这些更改可能导致 Scriptable Render Pass 生成不正确的结果。这意味着,当您使用HDR高动态范围
请参阅 词汇表
输出和在 AfterRenderingPostProcessing 注入点之后发生的 Scriptable Render Pass 时,您需要考虑 HDR 输出所做的更改。这同样适用于您希望在后期处理在图像显示在屏幕上之前,通过应用滤镜和特效来改善产品视觉效果的过程。例如,您可以使用后期处理特效来模拟物理相机和胶片属性,例如 Bloom 和景深。 更多信息 后期处理,后期处理,后期处理
请参阅 词汇表
期间或之后添加叠加层时,例如UI(用户界面) 允许用户与您的应用程序交互。Unity 目前支持三种 UI 系统。 更多信息
请参阅 词汇表
或其他摄像机一个组件,用于创建场景中特定视点的图像。输出要么绘制到屏幕上,要么捕获为纹理。 更多信息
请参阅 词汇表
的输出,因为您需要使用 HDR 输出产生的色域。为了使 Scriptable Render Pass 能够处理 HDR 输出所做的更改,您必须手动执行脚本中的色调映射和色彩空间转换

但是,如果您在 BeforeRenderingPostProcessing 注入点或之前添加 Scriptable Render Pass,则无需进行任何更改以使其与 HDR 输出兼容。这是因为 Unity 会在渲染 HDR 输出之前执行 Scriptable Render Pass。

注意:当您使用摄像机堆栈在 Unity 执行色调映射之前渲染摄像机输出时,可以避免此问题。然后,Unity 将 HDR 输出处理应用于堆栈中的最后一个摄像机。要了解如何设置摄像机堆栈,请参阅摄像机堆栈

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

为了使 Scriptable Render Pass 能够处理 HDR 输出对色彩空间和动态范围所做的更改,请使用 SetupHDROutput 函数将色调映射和色彩空间转换应用于 Scriptable Render Pass 所修改的材质。

  1. 打开包含您希望与 HDR 输出一起使用的 Scriptable Render Pass 的 C# 脚本。

  2. 在 Render Pass 类中添加一个名为 SetupHDROutput 的方法。

    以下脚本提供了一个如何使用 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 输出着色器在 GPU 上运行的程序。 更多信息
    请参阅 词汇表
    关键字以减少资源使用。

    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 中检索色调映射将图像的 HDR 值重新映射到适合在屏幕上显示的范围内的过程。 更多信息
    请参阅 词汇表
    组件。

    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 方法,以确保在使用此 Scriptable Render Pass 时始终考虑 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 输出的自定义叠加
图形性能和分析