Version: Unity 6.0 (6000.0)
언어 : 한국어
URP에서 HDR 출력 호환 커스텀 오버레이 구현
Shader Import Settings window reference

URP에서 HDR 출력으로 스크립터블 렌더 패스 문제 해결

HDR(High Dynamic Range) 출력은 톤 매핑과 색 공간 변환을 적용할 때 스크립터블 렌더 패스에 대한 입력을 변경합니다. 이러한 변화로 인해 스크립터블 렌더 패스가 잘못된 결과를 생성할 수 있습니다. 따라서__ HDR__하이 다이내믹 레인지
See in Glossary
출력 및 AfterRenderingPostProcessing 주입 지점 또는 그 이후에 발생하는 스크립터블 렌더 패스를 사용하는 경우, HDR 출력으로 인해 발생하는 변화를 고려해야 합니다. 이는 포스트 프로세싱 도중 또는 이후에 오버레이를 추가하려는 경우에도 마찬가지인데(예: UI 또는 다른 카메라의 출력), 이는 HDR 출력에 따른 색 영역을 사용해야 하기 때문입니다. 스크립터블 렌더 패스가 HDR 출력에 따른 변화와 함께 작동하도록 하려면 스크립트에서 수동으로 톤 매핑과 색 공간 전환을 수행해야 합니다.

그러나 BeforeRenderingPostProcessing 주입 지점 또는 그 이전에 스크립터블 렌더 패스를 추가하는 경우 HDR 출력과의 호환성을 위해 변경해야 할 것은 없습니다. 이는 Unity가 HDR 출력을 렌더링하기 전에 스크립터블 렌더 패스를 실행하기 때문입니다.

참고: Unity가 톤 매핑을 수행하기 전에 카메라 스택을 사용하여 카메라 출력을 렌더링하는 경우 이 문제를 방지할 수 있습니다. 이후 Unity는 스택의 마지막 카메라에 HDR 출력 처리를 적용합니다. 카메라 스택을 설정하는 방법은 카메라 스태킹을 참고하십시오.

스크립트의 톤 매핑 및 색 공간 전환

스크립터블 렌더 패스가 HDR 출력에 따른 색 공간 및 동적 범위의 변화와 함께 작동하도록 하려면 SetupHDROutput 함수를 사용하여 스크립터블 렌더 패스가 변경하는 머티리얼에 톤 매핑과 색 공간 변환을 적용합니다.

  1. HDR 출력과 함께 사용할 스크립터블 렌더 패스를 포함하는 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 출력 셰이더 키워드를 비활성화하여 리소스 사용량을 줄이십시오.

    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. 볼륨 관리자에서 톤 매핑 컴포넌트를 가져옵니다.

    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() 함수에서 Setup HDR Output 메서드를 호출하여 이 스크립터블 렌더 패스가 사용 중일 때마다 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