VR、ゲーム制作、プログラミング。Unity とか Oculus Rift とか。

2012年7月29日日曜日

[Unity]NGUIの複数パネル時のDrawCallメモ

NGUI の複数パネル時の DrawCall について、個人的に勘違いしていたのでメモ。

UIPanel を増やすと同じ Atlas を使っていても DrawCall が増えると思っていたのですが、そうでもないようです。

図の Panel2(緑) と Panel3(青) は同じ Atlas です。以下の図では、Panel1(赤、別 Atlas)が 2 と 3 の間の Z 座標になっていて、合計の DrawCall は 3 になっています。


一方、以下の図は Panel1 の Z 座標は 2 と 3 よりも奥になっていて、合計の DrawCall は 2 になっています。ソースまでは確認していませんが、おそらく同一 Atlas かつ間に他の Atlas を描画する必要のない 2 と 3 をまとめて描画してくれていると考えられます。


(NGUI の複数 Atlas 時の表示順序については [Unity]NGUIのDepth設定その2(複数Atlas) を参照)

NGUI のバージョンは v2.0.9a です。

公式ドキュメント ( NGUI: UIPanel » Tasharen Entertainment ) にはパネルを増やすと DrawCall が増えるように読める記述が見られる気がしますが、まとめてくれるならありがたいですね。

2012年7月18日水曜日

[Unity]2Dゲーム用パーティクル

2D ゲームのエフェクトに Unity のパーティクルシステムを使おうと思い、試してみました。

以下のようなパーティクルを作っていきます。


パーティクルシステムは Shuriken (Unity 3.5) です。

カメラの作成

まずはパーティクル撮影用カメラを作ります。2D 撮影用カメラとは別にします。上の画像では、青い背景は 2D 部分です。


Hierarchy の Create > Camera で新しいカメラを作成し、Culling Mask を 3D パーティクル用レイヤだけを写すように設定します。ここでは "3D Particle" というレイヤを新しく作成して使用しています(Layer > Add Layer...)。

カメラからパーティクルの距離によってパーティクルのサイズが変わらないように、Projection を Orthographic にします。

パーティクルは 2D 部分(GUI やキャラクターなど)より手前に表示したいので、カメラの Depth は 2D 撮影用カメラよりも大きな値にします。

2012/7/31 追記 : Clear Flags を Depth only にします。

パーティクルの作成

まず、星の画像素材を作成します。星の部分の色はパーティクルシステム側でつけるので、画像では白にしておきます。星のまわりは透明にします。

画像ができたらプロジェクトビューにドラッグします。マテリアルを作成し(Project の Create > Material)、インポートした画像を設定、シェーダは Unlit/Trasparent Colored あたりにしておきます。

いよいよパーティクルです。Hierarchy の Create > Particle System で新しいパーティクルシステムを作成し、パーティクル撮影用カメラの子にします。レイヤはパーティクル用のものに忘れずに変えておきます。表示されない場合はカメラの撮影範囲に入っているか確認しましょう。

Renderer に先ほど用意したマテリアルを設定します。

Start Color を黄色に、Start Delay, Start Lifetime, Start Speed, Start Size, Duration を適当に調整します(値は画像参照)。

Color over Lifetime を調整して、赤から黄色に、かつフェードアウトするようにします。バーの下側が乗算する色、上側がアルファ値です。

Size over Lifetime を調整して、パーティクルが徐々に大きくなるようにします。


Shapeを Cone, Angle=90, Radius=0 にして、Rotation を 0,-180,-180 にすると中心から放射状に広がります(上図)。


Shapeを Cone, Angle=0, Radius=0 にして、Rotation を -90,-180,-180 にすると直線的になります(上図)。


Shape を Cone, Angle=0, Radius=90 に、Velocity over Lifetime で Y=-0.5 に、Force over Lifetime で Y=2 に、Rotation を 0,-180,-180 にすると放射状に広がりつつ放物線を描きます(上図)。

これで大体 2D エフェクトに使えそうになってきました。

ただ、複数解像度対応のためにパーティクルを拡大縮小する場合、パーティクルシステムはカメラ側でのスケール変更の影響を受けないため、拡大縮小にはちょっとした処理が必要です。ということで、次回はパーティクルのスケーリングについて書く予定です。


2012/7/18 追記 : 説明がどの画像を指しているかわかりにくかったのを修正。
2012/7/31 追記 : カメラの Clear Flags を Depth only にするのを書き忘れていたので追記。

2012年7月4日水曜日

[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);
            }
        }
    }
}