この記事は
uGUIで自由なメッシュを表示する(5.0)とuGUIで自由なメッシュを表示する(5.3)
この2つの記事を統合したものです。
UnityのuGUIはImageやRawImage等単一スプライトの表示機能はちゃんと用意されていますが、これは1ゲームオブジェクトに付き1スプライトしか表示できません。
例えばマップチップを使いたいとき…なんかにはちょっと無駄感があります。
というわけで、uGUIを使って、好きなメッシュを表示する仕組みを調べました。
この記事はUnity5.3を元に記述しています。5.4以降変更される可能性は十分あります。
※5.7現在大きくは変わっていない模様。
Graphic
uGUIではGraphicクラスを継承しているものがCanvasRendererの描画対象になります。
このGraphicクラスを自分で継承してカスタマイズすることで好きなものを描画することが出来ます。
このクラスで特に重要なものがOnPopulateMeshとmainTextureです。
まず継承する
まずはGraphicを継承したクラスを用意します。
using UnityEngine; using UnityEngine.UI; using System.Collections.Generic; public class MyGraphic : Graphic { }
これだけで真っ白の四角が表示されます。
OnPopulateMesh
このOnPopulateMeshをオーバーライドして独自のメッシュを生成します。
このメソッドは定義がvoid OnPopulateMesh( VertexHelper vh )となっています。
引数のvhに頂点情報をAddUIVertexQuadメソッド等を利用して追加する事でそれがポリゴンとして描画されます。
以下具体例として試しに台形を描画します。
using UnityEngine; using UnityEngine.UI; public class MyGraphic : Graphic { protected override void OnPopulateMesh( VertexHelper vh ) { vh.Clear(); // 左上 UIVertex lt = UIVertex.simpleVert; lt.position = new Vector3( -50, 100, 0 ); lt.color = Color.green; // 右上 UIVertex rt = UIVertex.simpleVert; rt.position = new Vector3(50, 100, 0); rt.color = Color.red; // 右下 UIVertex rb = UIVertex.simpleVert; rb.position = new Vector3( 100, 0, 0 ); rb.color = Color.yellow; // 左下 UIVertex lb = UIVertex.simpleVert; lb.position = new Vector3( -100, 0, 0 ); lb.color = Color.white; vh.AddUIVertexQuad( new UIVertex[] { lb, rb, rt, lt } ); } }
vbo.AddUIVertexQuadに頂点の配列を追加します。
4頂点で1つの四角が描画されます。
わかりやすくする為すべての頂点で色を変更してます。
次に台形を2つに増殖させてみます。
using UnityEngine; using UnityEngine.UI; public class MyGraphic : Graphic { protected override void OnPopulateMesh( VertexHelper vh ) { vh.Clear(); // 左上 UIVertex lt = UIVertex.simpleVert; lt.position = new Vector3( -50, 100, 0 ); lt.color = Color.green; // 右上 UIVertex rt = UIVertex.simpleVert; rt.position = new Vector3(50, 100, 0); rt.color = Color.red; // 右下 UIVertex rb = UIVertex.simpleVert; rb.position = new Vector3( 100, 0, 0 ); rb.color = Color.yellow; // 左下 UIVertex lb = UIVertex.simpleVert; lb.position = new Vector3( -100, 0, 0 ); lb.color = Color.white; vh.AddUIVertexQuad( new UIVertex[] { lb, rb, rt, lt } ); // 2つめの四角を300下に lt.position.y -= 300; rt.position.y -= 300; rb.position.y -= 300; lb.position.y -= 300; vh.AddUIVertexQuad( new UIVertex[] { lb, rb, rt, lt } ); } }
4頂点毎に四角が1つ作られるという仕様のようです。
3頂点だけの場合は例外が発生し表示がされませんでした。
mainTextureの指定
テクスチャの設定方法ですが、これはmainTextureプロパティをオーバーライドして、設定したいテクスチャを返すようにします。
using UnityEngine; using UnityEngine.UI; public class MyGraphic : Graphic { /// <summary> /// メッシュに設定するテクスチャの指定 /// </summary> public override Texture mainTexture { get { // ここで設定したいテクスチャを返すようにする return base.mainTexture; } } }
Inspector上でテクスチャを設定して、このgetプロパティで返すようにします。
using UnityEngine; using UnityEngine.UI; 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; public class MyGraphic : Graphic { /// <summary> /// メッシュに設定したいテクスチャをここで指定 /// </summary> [SerializeField] private Texture2D texture_; /// <summary> /// メッシュに設定するテクスチャの指定 /// </summary> public override Texture mainTexture { get { // ここで設定したいテクスチャを返すようにする return texture_; } } protected override void OnPopulateMesh( VertexHelper vh ) { vh.Clear(); // 左上 UIVertex lt = UIVertex.simpleVert; lt.position = new Vector3( -50, 100, 0 ); lt.uv0 = new Vector2(0, 1); // 右上 UIVertex rt = UIVertex.simpleVert; rt.position = new Vector3(50, 100, 0); rt.uv0 = new Vector2(1, 1); // 右下 UIVertex rb = UIVertex.simpleVert; rb.position = new Vector3( 100, 0, 0 ); rb.uv0 = new Vector2(1, 0); // 左下 UIVertex lb = UIVertex.simpleVert; lb.position = new Vector3( -100, 0, 0 ); lb.uv0 = new Vector2(0, 0); vh.AddUIVertexQuad( new UIVertex[] { lb, rb, rt, lt } ); // 2つめの四角を300下に正方形で lt.position.y -= 300; rt.position.y -= 300; rb.position.y -= 300; rb.position.x = 50; lb.position.y -= 300; lb.position.x = -50; vh.AddUIVertexQuad( new UIVertex[] { lb, rb, rt, lt } ); } }
台形だとテクスチャがゆがんでわかりにくいので下は正方形にしてます。
注意点1
マテリアルも指定できますが_MainTexプロパティは上記のmainTextureの返り値で上書きされてしまいます。
そのためマテリアル側のテクスチャの反映がされない…!?という時は_MainTexにテクスチャを指定していないか確認してみてください。
注意点2
OnPopulateMeshは更新が必要なタイミングでしか呼ばれません。
具体的にはGraphicのSet**Dirtyメソッドが呼ばれたり、Canvasの設定が何か変更されたり…といったタイミングです。
なので頂点のアニメーションをこのメソッドに入れたりしているとうまく動かないです。
注意点3
マテリアルは1つしか設定できません。
MeshRendererだとサブメッシュを利用する事で複数のマテリアルが利用できましたが、こっちはそういうのはありません。
そういう場合はゲームオブジェクトを別に分ける他ありません。
※5.2ではOnPopulateMesh(Mesh mesh)を利用しましたが、5.3でこれは非推奨になりました。
注意点4
OnPopulateMeshの引数に渡されるVertexHelperの頂点情報は保持され続けます。
自分でClearを呼ぶなどしなければAddした分だけ頂点情報がどんどん増えていきます。
また、頂点情報の更新が無い場合はOnPopulateMesh呼び出し時に何もしない事でパーフォーマンスの向上が見込めると思います。
感想
基本はこんな感じです。
これでマップチップ実装したくなった時も無駄に大量のゲームオブジェクトを量産しなくてよくなります。
コメント
[…] Unity – Unityで線を描画したい(109826)|teratail uGUIで自由なメッシュを表示する(5.3統合版) […]