uGUIで自由なメッシュを表示する

UnityのuGUIはImageやRawImage等単一スプライトの表示機能はちゃんと用意されていますが、これは1ゲームオブジェクトに付き1スプライトしか表示できません。

例えばマップチップを使いたいとき…なんかにはちょっと無駄感があります。

というわけで、uGUIを使って、好きなメッシュを表示する仕組みを調べました。

 

※Unity5.2からOnFillVBOは非推奨になりました。(というか表示されなかった…)

→ 以下の記事を参照してください。

uGUIで自由なメッシュを表示する(5.3統合版)
この記事は uGUIで自由なメッシュを表示する(5.0)とuGUIで自由なメッシュを表示する(5.3) この2つの記事を統合したものです。 UnityのuGUIはImageやRawImage等単一スプライト...

 

Graphic

uGUIではGraphicクラスを継承しているものがCanvasRendererの描画対象になります。

このGraphicクラスを自分で継承してカスタマイズすることで好きなものを描画することが出来ます。

このクラスで特に重要なものがOnFillVBOとmainTextureです。

まず継承する

まずはGraphicを継承したクラスを用意します。

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

[RequireComponent( typeof( CanvasRenderer ) )]
[RequireComponent( typeof( RectTransform ) )]
public class MyGraphic
	: Graphic
{
}

ついでに、GraphicはCanvasRendererとRectTransformが必須なので属性をつけて要求しておきます。

これだけで真っ白の四角が表示されます。

InheritGraphic1

 

OnFillVBO

このOnFillVBOをオーバーライドして独自のメッシュを生成します。

このメソッドは定義がvoid OnFillVBO( List<UIVertex> vbo )となっています。

引数のvboに頂点情報をAddメソッドで追加する事でそれがポリゴンとして描画されます。

以下具体例として試しに台形を描画します。

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

/// <summary>
/// 独自のUI描画
/// </summary>
[RequireComponent( typeof( CanvasRenderer ) )]
[RequireComponent( typeof( RectTransform ) )]
public class MyGraphic
    : Graphic
{
    /// <summary>
    /// ここでメッシュを生成する
    /// </summary>
    /// <param name="vbo">Vbo.</param>
    protected override void OnFillVBO( List<UIVertex> vbo )
    {
        UIVertex v = UIVertex.simpleVert;

        // 左下
        v.position = new Vector3( -100, 0, 0 );
        v.color = Color.white;
        vbo.Add( v );

        // 右下
        v.position = new Vector3( 100, 0, 0 );
        v.color = Color.yellow;
        vbo.Add( v );

        // 右上
        v.position = new Vector3( 50, 100, 0 );
        v.color = Color.red;
        vbo.Add( v );

        // 左上
        v.position = new Vector3( -50, 100, 0 );
        v.color = Color.green;
        vbo.Add( v );
    }
}

vbo.Addで頂点を追加します。

4頂点で1つの四角が描画されます。

わかりやすくする為すべての頂点で色を変更してます。

InheritGraphics2_overrideOnFillDraw

次に台形を2つに増殖させてみます。

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

/// <summary>
/// 独自のUI描画
/// </summary>
[RequireComponent( typeof( CanvasRenderer ) )]
[RequireComponent( typeof( RectTransform ) )]
public class MyGraphic
    : Graphic
{
    /// <summary>
    /// ここでメッシュを生成する
    /// </summary>
    /// <param name="vbo">Vbo.</param>
    protected override void OnFillVBO( List<UIVertex> vbo )
    {
        UIVertex v = UIVertex.simpleVert;

        // 左下
        v.position = new Vector3( -100, 0, 0 );
        v.color = Color.white;
        vbo.Add( v );
        // 右下
        v.position = new Vector3( 100, 0, 0 );
        v.color = Color.yellow;
        vbo.Add( v );
        // 右上
        v.position = new Vector3( 50, 100, 0 );
        v.color = Color.red;
        vbo.Add( v );
        // 左上
        v.position = new Vector3( -50, 100, 0 );
        v.color = Color.green;
        vbo.Add( v );

        // 2つめの四角を300下に

        // 左下
        v.position = new Vector3( -100, -300, 0 );
        v.color = Color.white;
        vbo.Add( v );
        // 右下
        v.position = new Vector3( 100, -300, 0 );
        v.color = Color.yellow;
        vbo.Add( v );
        // 右上
        v.position = new Vector3( 50, -200, 0 );
        v.color = Color.red;
        vbo.Add( v );
        // 左上
        v.position = new Vector3( -50, -200, 0 );
        v.color = Color.green;
        vbo.Add( v );
    }
}

InheritGraphics3_overrideOnFillDrawx2

4頂点毎に四角が1つ作られるという仕様のようです。

ちなみに3頂点だけにしたらUnityが死にました…

 

mainTextureの指定

テクスチャの設定方法ですが、これはmainTextureプロパティをオーバーライドして、設定したいテクスチャを返すようにします。

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

/// <summary>
/// 独自のUI描画
/// </summary>
[RequireComponent( typeof( CanvasRenderer ) )]
[RequireComponent( typeof( RectTransform ) )]
public class MyGraphic
    : Graphic
{
    /// <summary>
    /// メッシュに設定するテクスチャの指定
    /// </summary>
    public override Texture mainTexture
    {
        get
        {
            // ここで設定したいテクスチャを返すようにする
            return base.mainTexture;
        }
    }
}

Inspector上でテクスチャを設定して、このgetプロパティで返すようにします。

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

/// <summary>
/// 独自のUI描画
/// </summary>
[RequireComponent( typeof( CanvasRenderer ) )]
[RequireComponent( typeof( RectTransform ) )]
public class MyGraphic
    : Graphic
{
    /// <summary>
    /// メッシュに設定したいテクスチャをここで指定
    /// </summary>
    [SerializeField]
    private Texture texture_;

    /// <summary>
    /// メッシュに設定するテクスチャの指定
    /// </summary>
    public override Texture mainTexture
    {
        get
        {
            // ここで設定したいテクスチャを返すようにする
            return texture_;
        }
    }
}

次にUVの指定を行います。

ついでに頂点カラーの指定があると、少し見づらいので白に変更してます。

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

/// <summary>
/// 独自のUI描画
/// </summary>
[RequireComponent( typeof( CanvasRenderer ) )]
[RequireComponent( typeof( RectTransform ) )]
public class MyGraphic
    : Graphic
{
    /// <summary>
    /// メッシュに設定したいテクスチャをここで指定
    /// </summary>
    [SerializeField]
    private Texture texture_;

    /// <summary>
    /// メッシュに設定するテクスチャの指定
    /// </summary>
    public override Texture mainTexture
    {
        get
        {
            // ここで設定したいテクスチャを返すようにする
            return texture_;
        }
    }

    /// <summary>
    /// ここでメッシュを生成する
    /// </summary>
    /// <param name="vbo">Vbo.</param>
    protected override void OnFillVBO( List<UIVertex> vbo )
    {
        UIVertex v = UIVertex.simpleVert;

        // 台形
        // 左下
        v.position = new Vector3( -100, 0, 0 );
        v.uv0 = new Vector2( 0, 0 );
        vbo.Add( v );
        // 右下
        v.position = new Vector3( 100, 0, 0 );
        v.uv0 = new Vector2( 1, 0 );
        vbo.Add( v );
        // 右上
        v.position = new Vector3( 50, 100, 0 );
        v.uv0 = new Vector2( 1, 1 );
        vbo.Add( v );
        // 左上
        v.position = new Vector3( -50, 100, 0 );
        v.uv0 = new Vector2( 0, 1 );
        vbo.Add( v );

        // 正方形
        // 左下
        v.position = new Vector3( -50, -200, 0 );
        v.uv0 = new Vector2( 0, 0 );
        vbo.Add( v );
        // 右下
        v.position = new Vector3( 50, -200, 0 );
        v.uv0 = new Vector2( 1, 0 );
        vbo.Add( v );
        // 右上
        v.position = new Vector3( 50, -100, 0 );
        v.uv0 = new Vector2( 1, 1 );
        vbo.Add( v );
        // 左上
        v.position = new Vector3( -50, -100, 0 );
        v.uv0 = new Vector2( 0, 1 );
        vbo.Add( v );
    }
}

台形だとテクスチャがゆがんでわかりにくいので下は正方形にしてます。

InheritGraphics4_overrideSetUV

 

注意点1

マテリアルも指定できますが_MainTexプロパティは上記のmainTextureの返り値で上書きされてしまいます。

そのためマテリアル側のテクスチャの反映がされない…!?という時は_MainTexにテクスチャを指定していないか確認してみてください。

 

注意点2

OnFillVBOは更新が必要なタイミングでしか呼ばれません。

具体的にはGraphicのSet**Dirtyメソッドが呼ばれたり、Canvasの設定が何か変更されたり…といったタイミングです。

なので頂点のアニメーションをこのメソッドに入れたりしているとうまく動かないです。

 

注意点3

マテリアルは1つしか設定できません。

MeshRendererだとサブメッシュを利用する事で複数のマテリアルが利用できましたが、こっちはそういうのはありません。

そういう場合はゲームオブジェクトを別に分ける他ありません。

 

感想

基本はこんな感じです。

これでマップチップ実装したくなった時も無駄に大量のゲームオブジェクトを量産しなくてよくなります。

NGUIがベースになってるだけあって、 この辺りは良く似ているなーと思いました。

タイトルとURLをコピーしました