[Unity]NGUIのDepth設定その2(複数Atlas)

NGUI で複数の Atlas 利用時には、前後関係は Depth ではなく Z 座標で決まるというのは以前 [Unity]NGUIのDepth設定 に書いたのですが、これが結構くせがありました。

単一の Widget 同士なら単純に Z 座標が小さいほうが手前になりますが、複数の場合「同一 Atlas の Widget の Z 座標の平均値」が小さいほうの Widget 全てが、もう一方の全てより手前になるようです。


上図で、SciFi Label 1, 2 と Fantasy Label 1, 2 はそれぞれ同じ Atlas を利用しています。Fantasy Label 1 は Z=1 と 4 つの中で最も Z 座標が大きいですが、Fantasy Label 2 が Z=-3 であるため平均は Z=-1、一方の SciFi Label 1 と 2 の平均は (0 + -1)/2 = -0.5 となり、Fantasy Label 1 も SciFi Label 1, 2 より手前になっています。

普通は「手前 : Fantasy 2 > SciFi 2 > SciFi 1 > Fantasy 1 : 奥」を期待すると思うんですけどね。ちなみに、上の状態で DrawCall=2 です。

では、期待通りにするにはどうするかと言うと、一つは Panel の Depth Pass にチェックを入れることです。…が、アルファブレンディングが犠牲になる上に DrawCall=4 になるため、これは正直使わないと思います(そもそも用途が違いそう)。


結局、Panel を増やすことで、下図のような表示を得ることができました。DrawCall=3 です。


なお、ここでは Panel だけ Z 座標を順序付けし、Widget の Z は全て 0 にしています。実際の表示順序は各 Panel 配下の Widget の絶対 Z 座標の平均で決まるため、上図で Fantasy 1 の Z を -3 にしたり、Panel 1 にもう一つ Widget を追加して Z=-5 にすると、Fantasy 1 が一番手前になります。
 
NGUI のバージョンは v2.0.9a でした。

おまけ

検証中に、あるオブジェクト配下の全ての Widget の Z 座標を -Depth にするスクリプトを書きましたが、上記の挙動のためあまり役に立ちそうもありませんでした。一応貼っておきます。

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class OrderAdjuster : MonoBehaviour
{
    void Update () { AdjustZ(transform); }
    
    void AdjustZ (Transform tf) {
        foreach (Transform child in tf) {
            UIWidget widget = child.GetComponent<UIWidget>();
            if (widget) {
                child.localPosition = new Vector3(
                    child.localPosition.x,
                    child.localPosition.y,
                    -(float)widget.depth);
            } else {
                AdjustZ(child);
            }
        }
    }
}

コメント