【Unity】UnityにおけるHDRレンダリング関連の設定とその挙動

UnityでHDRレンダリングする際の設定項目と、その挙動を確認してみました。

HDRレンダリングに必要なもの

HDRレンダリングが通常のレンダリングと違う点は次の通りです。

以下、これらの設定方法と挙動を確認していきます。

HDRテクスチャを扱う

HDRテクスチャとはRGBに1以上の値を格納できるテクスチャです。
EXRやHDRといったHDR対応フォーマットのテクスチャをインポートすれば使えます。

docs.unity3d.com

ただしこのテクスチャを取り扱う場合は処理負荷が高く使用メモリも増えます。
そのため、擬似HDRテクスチャと呼ばれる、α値をうまく使ってLDRテクスチャにHDR情報を格納したテクスチャも使われるようです。

news.mynavi.jp

HDR光源を扱う

光源をHDR化するにはLightコンポーネントのIntensityを上げるだけです。 Lightの色にIntensityを乗算した値がシェーダに渡されます。

ただしリニア空間の場合はデガンマされるので注意が必要です。

light11.hatenadiary.com

浮動小数点バッファ

ブルームなどのポストエフェクトでHDR値を取り扱うには、
レンダーターゲットを浮動小数点バッファにしなければいけません。

これは以下の手順で設定できます。

  • Edit > Project Settings > Graphics > Tier Settings > Use HDRをtrueに
  • Camera > Allow HDRをtrueに

ちなみにTier SettingsのHDR ModeではFP16の他にR11G11B10が選べます。
これは32ビットのバッファになるのでメモリにも処理負荷的にも優しくなります。
検証が必要ですが、諸々の条件が合うならこっちを使ったほうがよさそうです。

docs.unity3d.com

浮動小数点バッファの挙動を確認する

ちゃんとレンダーターゲットが変わっているか確認してみましょう。
まず、次のようなシェーダを書きます。

Shader "WriteHDRValue"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
            CGPROGRAM
           #pragma vertex vert
           #pragma fragment frag
            
           #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 pos : TEXCOORD0;
            };

            sampler2D _MainTex;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.pos = o.vertex.xyw;
                o.pos.y *= _ProjectionParams.x;
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                half2 uv = i.pos.xy / i.pos.z * 0.5 + 0.5;
                return uv.x * 3.0f;
            }
            ENDCG
        }
    }
}

ビューポート座標のxを3倍したものを出力しています。
レンダーターゲットが浮動小数点バッファになっている場合には0~3の値が書き込まれるはずです。
なっていない場合は1より大きい値が丸められて0~1が書き込まれます。

次にポストエフェクトのシェーダを書きます。

Shader "DecodeHDRPostEffect"
{
    Properties{
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Cull Off
        ZTest Always
        ZWrite Off

        Tags { "RenderType"="Opaque" }

        Pass
        {
            CGPROGRAM
           #pragma vertex vert
           #pragma fragment frag
            
           #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                col.rgb /= 3;
                return col;
            }
            ENDCG
        }
    }
}

今度は入力色を3で割って出力しています。
レンダーターゲットが浮動小数点バッファになっていれば0〜1の値が得られます。
なっていない場合は上述の通り丸められた部分の色情報が失われて、0〜1/3の値が得られます。

1つ目のシェーダを適当なオブジェクトに適用し、
2つ目のシェーダをポストエフェクトに使うと結果は次のようになります。

f:id:halya_11:20180802133707g:plain

これで浮動小数点バッファに書き込まれていることが確認できました。

参考

news.mynavi.jp

news.mynavi.jp