太郎Work

Unityとかで困ったこと等を残しておきます

NGUIではないオブジェクトをNGUIの手前に描画する方法

※追記 3.0.6あたりから仕様が変わり、細かく指定できるようになったため以下の様なことを気にする必要がなくなりました

先日、NGUIが3.0にアップデートされUIPanelの挙動が大幅に変更されていました。

そこで結構困惑したのでついでに2.0系含めてまとめておきます。

2.0系(2.7では3.0の挙動と切り替え可能)はUIPanel単位でUIWidgetを収集して描画リクエストを送る仕様になっていて、

描画順は

  1. UIPanelの中に含まれている同一Materialを持つUIWidgetのZ値を平均化
  2. Z値を平均化した上でdepth設定に基づいた頂点座標・カラー順でメッシュを生成
  3. Mobile/Particles/Alpha Blended等で描画(DrawCall 1)

この仕様は内部仕様を把握すれば、DrawCall及び描画順を完全に操作することができるので個人的には非常に扱いやすかったのですが、慣れないと特に上記の1の仕様によりかなりカオスな事になります。

例えば単一UIPanel内に以下の3つが含まれている場合大変なことになります。

Widget1(material1,z=-5f,depth0)
Widget2(material2,z=-1f,depth1)
Widget3(material1,z=5f,depth2)

マテリアルが同じなWidget1,3が1DrawCallとなり平均化されz=0にdepthが低い順に描画。

Widget2は-1fなので手前に描画され、完全に意図していない順になってしまいます。

意図したとおりにするにはWidget3(又は1)だけUIPanelを分離すればいいのですが、階層構造がかなり複雑になってきます。

そこでNGUI3.0では完全にdepthで操作できるようになり、上記のようなサンドウィッチ状の場合は自動でDrawCallを分けてくれます。Z値は気にする必要がありません。


そして本題ですが、この副作用として内部的にMaterialを複製するため、自分で作ったシェーダパラメータを変更しようとすると更新が定期的なためにカクカクしたような表示になってしまいます。

そこでUnityのQuadメッシュを使って描画しようとすると今度は表示されない!

理由は、今回からMaterialのRenderQueueをDrawCall分だけ足し算するようなっており、実質強制最前面で描画されているためです。(もしかしたら仕様がそのうち変更されるかもしれません)

この辺りのコードはUIDrawCall.cs辺りまで読まないと何が起きているか分からないのでかなり躓きました。。。

解決策として背景画像となっているWidgetのRenderQueueを引き算しておくか、メッシュのRenderQueueを大きめな値に指定しておくと想定通りの描画になりました。

細かい描画順はUIWidgetからUIDrawCallを取得してrenderQueueの値を見ることで調整できます。

この仕様を見ると本当にボタン等のインターフェースのみでNGUIを利用して背景やメインゲームは他のもので作ってねという意味合いが込められてるのかもしれません。

長くなってしまいましたが、検証に時間を掛けているわけでもないので間違っている部分がありましたらご指摘よろしくお願いします。

読みにくくて申し訳ないです。


ちなみにNGUI3.0からはdepth操作が大量に発生しますが、depthを一括変更するには UIWidgetを複数選択してNGUI->Selection->Adjust Depth ショートカットキーが設定されているので複数回押すことで全体を+10とかが可能です。

Bring To Frontを使えば最前面に持ってくることも可能 最初はこれに気づかず一個ずつ値を変更していました…

以上、慣れると便利なNGUI3.0の話でした。