Version: 6000.3
语言: 中文
在 URP 中实现与 HDR 输出兼容的自定义叠加层
着色器导入设置窗口参考

在URP中使用HDR输出的可脚本渲染通道问题排查

高动态范围(HDR)输出在应用色调映射和色彩空间转换时,会更改可编写脚本渲染通道的输入。这些更改可能会导致可编写脚本的渲染通道产生不正确的结果。这意味着当您使用HDR高动态范围
请参阅术语表
输出和 AfterRenderingPostProcessing 注入点中或之后发生的可脚本渲染通道,你需要考虑 HDR 输出所做的更改。当您想要在期间或之后添加叠加层时,这也适用后处理在图像出现在屏幕上之前通过应用滤镜和效果来改善产品视觉效果的过程。你可以使用后期处理效果来模拟物理摄像机和胶片属性,例如泛光和景深。更多信息 后处理, 后处理, 后处理
术语表中查看
,例如 UI 或其他相机在场景中创建特定视点图像的组件。输出要么绘制到屏幕上,要么作为纹理捕获。更多信息
请参阅术语表
,因为您需要使用 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 输出着色器在 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. 检索色调映射将图像的 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 方法,以确保每当使用此可编写脚本的渲染通道时,都会考虑 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 输出兼容的自定义叠加层
着色器导入设置窗口参考