【Unity】不透明キューの描画順が手前からじゃない件

Unityで不透明のオブジェクトを描画する際にはシェーダのQueueにGeometryを指定します。
このような不透明オブジェクトの描画は手前からされるものだと思ってましたが、そんなこともなさそうなのでメモです。

Unity5.6.1

検証

レンダリング順序の検証用に次のようなシェーダを作ります。

Shader "CustomShader1" {
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue"="Geometry" }

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

            struct appdata
            {
                half4 vertex : POSITION;
            };

            struct v2f
            {
                half4 pos : SV_POSITION;
            };

            half4 _Color;
            
            v2f vert (appdata v)
            {
                v2f o = (v2f)0;
                o.pos = UnityObjectToClipPos(v.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                return 1;
            }
            ENDCG
        }
    }
}

次に、下図のようにシーンを作ります。

f:id:halya_11:20180409221913p:plain

手前から描画されるのであれば、Object3 > Object2 > Object1の順番に描画されるはずです。
まずこれらのオブジェクトに同じシェーダを設定してレンダリングしてみます。

結果は次のようになりました。

f:id:halya_11:20180409222238p:plain

手前から描画されています。
次に、上で作ったシェーダを3つに複製してそれぞれのオブジェクトに設定してみます。

f:id:halya_11:20180409222116p:plain

なぜかObject3 > Object1 > Object2の順番になりました。

ここまででひとまず、不透明キューにおける描画順がカメラからの距離だけに依存するわけではないことがわかりました。

不透明の描画順はどのように決まるのか?

それでは描画順はどのように決まるのでしょうか?
OpaqueSortModeのマニュアルにそれらしい記述がありました。

Unity - Scripting API: OpaqueSortMode

つまり、ざっくり下記のような感じです。

  • 不透明なオブジェクトはCPUやGPUを最適化するために様々な基準でソートされる
  • デフォルトではだいたい手前から奥へのソートが行われる
  • ただ、GPUによってはこれは意味をなさないので、デフォルトで距離ソートをかけないものもある

距離によるソートは厳密なものではないし、GPUによってはそもそも距離によるソートをしていないようです。

カメラのopaqueSortModeを設定すればソートモードを変更できますが、
これをFrontToBackにしたところで下記のように設定されるだけで、厳密に手前から描画されるわけではなさそうです。

Do rough front-to-back sorting of opaque objects.

厳密に描画順を制御したいならQueueの数値で管理しろということですね。

透明パスのレンダリング

透明パスは(当たり前ですが)厳密にソートされていて、奥にあるオブジェクトから順にレンダリングされます。

Unity - Scripting API: TransparencySortMode

参考サイト

Unity - Scripting API: OpaqueSortMode

Unity - Scripting API: TransparencySortMode