ハイダイナミックレンジ (HDR) 出力は、トーンマッピングと色空間変換を適用するときに、入力をスクリプタブルレンダーパスに変更します。これらの変更により、スクリプタブルレンダーパスが誤った結果を生む可能性があります。つまり、HDR 出力を使用して、AfterRenderingPostProcessing 投入ポイント以降にスクリプタブルレンダーパスを実行する場合は、HDR 出力によって生じる変更に対処する必要があるということです。このことは、UI や他のカメラからの出力など、オーバーレイをポストプロセス以降に加える場合にも当てはまります。なぜなら、HDR 出力によって生じる色域に対応する必要があるからです。スクリプタブルレンダーパスが HDR 出力による変更に適応できるようにするには、スクリプトでのトーンマッピングと色空間変換 を手動で行う必要があります。
ただし、スクリプタブルレンダーパスを BeforeRenderingPostProcessing 投入ポイント以前に加える場合は、HDR 出力に適応させるための変更は必要はありません。これは、Unity がスクリプタブルレンダーパスを実行してから、HDR 出力をレンダリングするためです。
ノート: Unity がトーンマッピングを実行する前に、カメラスタックを使用してカメラ出力をレンダリングすると、この問題を回避できます。その後、Unity はスタック内の最後のカメラに HDR 出力処理を適用します。カメラスタックの設定方法については、カメラスタック を参照してください。
HDR 出力によって変更された色空間とダイナミックレンジに、スクリプタブルレンダーパスが適応できるようにするには、スクリプタブルレンダーパスが変更するマテリアルに対してトーンマッピングと色空間変換を適用します。それには SetupHDROutput 関数を使用します。
HDR 出力とともに使用するスクリプタブルレンダーパスを含む C# スクリプトを開きます。
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
}
}
HDR 出力がアクティブかどうかの確認と、カメラのポストプロセスが有効になっているかどうの確認のための if ステートメントを加えます。いずれかの条件が満たされない場合は、リソースの使用を減らすために、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);
}
}
ディスプレイから輝度情報を取得して格納するための変数を以下のように作成します。
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);
}
Volume Manager から tonemapping コンポーネントを取得します。
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;
}
tonemapping コンポーネントが存在するかどうかを確認するために、別の if ステートメントを追加します。tonemapping コンポーネントが見つかった場合は、ディスプレイの輝度データをオーバーライドできます。
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;
}
}
}
ディスプレイとトーンマッピングからの輝度データを使用して、マテリアルの輝度プロパティを設定します。
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 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);
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);
このスクリプタブルレンダーパスを使用するときにはいつも HDR 出力に対処するように、Execute() 関数で SetupHDROutput メソッドを呼び出します。
以下はこの例の完全なコードです。
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);
}
}
}