渋谷ほととぎす通信

完全趣味でやってるUnityメモ。説明できないところを説明できるようにするための個人ブログ。昨日の自分より少しでも大きくなれるように。。。 ※所属団体とは一切関係がありません

Unity 動的にメッシュを生成してゴニョゴニョする : 超基本編


f:id:esakun:20150730215258g:plain:w450

仕事で実践することはほぼ無いですが、Unityでメッシュを動的に生成してみます。
色々調べてみるとUnityでもメッシュは作成できるという事が分かりました。
ということで「実際にやってみよう!」という、かなり初心者向けの記事です。

動的にメッシュを生成するシリーズの一貫です。

1.とりえず三角形メッシュを1つ表示してみる

僕は基礎を学ぶのが好きなので、WebGL、DirectXそれぞれで三角形描画をやりました。

生のWebGLで三角形描画
生のWebGLで三角形を描画するショートコード - 渋谷ほととぎす通信

C#で書くDirectXで三角形描画
C#でDirectX11 SlimDXで三角形を描画する - 渋谷ほととぎす通信

これらになぞられる形で今回も1個の三角形メッシュをUnityで動的に表示させてみます。


メッシュというのは一般的にポリゴンメッシュの事を指します。
ポリゴンメッシュとは3Dオブジェクトを表す「頂点・辺・面」の集合体の事です。

一般的に表示できるメッシュは3点もしくは4点を結んだ三角形メッシュ四角形メッシュです。Unityは三角形メッシュと四角形メッシュ両方に対応しています。

f:id:esakun:20151129152423p:plain:w200

こんな感じの1辺2メートルの三角形メッシュを表示してみます。
※Unityの単位はメートル

動的に三角形を描画する、MonoBehaviourを継承したDynamicCreateMeshクラスというものを作成しました。再生時に、このコンポーネントをGameObjectにAddComponentすると三角形が描画されます。

DynamicCreateMesh.cs

1つ1つ処理の内容を見ていきましょう。

1-1. Meshクラスでメッシュを生成

動的にメッシュを作るためにMeshインスタンスを作成します。

◆10行目辺り

var mesh = new Mesh ();
mesh.vertices = new Vector3[] {
    new Vector3 (0, 1f),
    new Vector3 (1f, -1f),
    new Vector3 (-1f, -1f),
};
mesh.triangles = new int[] {
    0, 1, 2  
};

生成したMeshインスタンスには下記の2要素が必要です。

  • 頂点座標配列
  • 頂点を結ぶ順番配列

頂点座標配列(verticesプロパティ)は言葉の通りメッシュを構築する頂点の3Dローカル座標の配列です。
頂点を結ぶ順番配列(trianglesプロパティ)はメッシュを正しく表示させるためにとても重要な情報で、いわゆるインデックスバッファです。

Unityは時計回りに頂点を結んだ面が前面(法線の向き)になります。シェーダのカリング設定がデフォルトであれば前面にメッシュが表示されます。

もしメッシュが表示されない、表示がおかしいなどあれば、この頂点を結ぶ順番、またはシェーダを見直すと良いです。

◆19行目辺り

mesh.RecalculateNormals ();

またRecalculateNormalsメソッドで法線方向の再計算を行います。 これを呼ばないと法線方向が(0, 0, 1)固定になってしまうので、特に理由がない場合は必ず呼ぶことになるでしょう。

1-2. メッシュを表示するために必要なもの

MeshFilterコンポーネント

Unityでメッシュを表示させるためにはMeshRendererクラス、またはSkinnedMeshRendererクラスが必要です。今回のメッシュはスキニングされていないため、MeshRendererクラスを使用することになります。 ※スキニングメッシュとはボーンを使って頂点を動的に動かすことが出来るメッシュのことです。例えばUnity-chanはスキニングされたメッシュで動いています。

MeshRendererに加えMeshFilterクラスも必要です。

Mesh Filter はアセットからメッシュを取得し、画面上でのレンダリングするために、メッシュレンダラー に渡します。

メッシュフィルター - Unity マニュアルより

マニュアルに記載されているように、MeshFilterクラスはMeshデータをMeshRendererに渡すために必要です。メッシュデータを直接レンダラーに渡さない仕様にしているのは、MeshFilterを通すことでMeshRendererSkinnedMeshRendererをフィルタリングして事故を減らしてくれているのではないかと勝手に思っています。

var filter = GetComponent<MeshFilter> ();
filter.sharedMesh = mesh;

このようにMeshFilterに先ほど作成したMeshインスタンスを渡します。


[RequireComponent (typeof(MeshRenderer))]
[RequireComponent (typeof(MeshFilter))]

念のための処理ですが、MeshFilterコンポーネントとMeshRendererコンポーネントはメッシュを表示するためには必ず必要なので、RequeireComponentアトリビュートを使ってDynamicCreateMeshコンポーネントをAddComponentした時に自動でアタッチするようにしています。


f:id:esakun:20151129153339p:plain:w200
三角形が無事に表示されました。

2.メッシュを着色する

三角形ポリゴンは表示されましたが、ピンク色になってしまいました。
Materialの設定が無い場合、Unityは親切にこのようなアラート表示をしてくれます。
ちなみにWebGLやDirectXでは何も表示されないので、何が原因なのかを探らねばならないため、原因がすぐに分かるUnityは神だと言えます。

次回記事で頂点カラーを使ったカラー描画をしています。参考にどうぞ。

Materialの設定

Materialの設定というか、この三角形のシェーダを正しくアサインする作業をしていきます。


f:id:esakun:20151129162857p:plain

Project > CreateボタンからSampleMaterialという名前でMaterialオブジェクトを作成します。


f:id:esakun:20151129162853p:plain

SampleMaterialを選択状態にして、ShaderをUnityのビルトインシェーダUnlit/Colorに設定し、Main Colorに適当な色を設定します。ちなみにUnlit/Colorシェーダは指定したカラーを全てのピクセルに描画する処理をします。


DynamicCreateMeshクラスのソースを一部変更し、Materialを反映できるようにします。

f:id:esakun:20151129162716p:plain
SampleMaterialをDynamicCreateMeshコンポーネントにアタッチできるようになります。


f:id:esakun:20151129163335p:plain:w200
この状態で実行すると、このように黄色い三角形メッシュが表示されるようになりました。

3.画像を貼ってみる

頂点カラーで三角形を表示していましたが、テクスチャマッピングに移ります。

f:id:esakun:20151129164400p:plain:w200

この画像(テクスチャ)をメッシュに貼り付けてみようと思います。


f:id:esakun:20151129164546p:plain:w200

先ほど作ったSampleMaterialを選択し、シェーダをUnlit/Textureに変更してテクスチャを設定します。

実行!!

f:id:esakun:20151129164930p:plain:w200

すると予想に反して青い三角形が表示されます。

UV座標の設定

なぜテクスチャが表示されず青い三角形が表示されたのかというと、各頂点に対してUV座標が設定されていなかったからです。

テクスチャを貼る場合は各頂点に対しUV座標を設定する必要があるため、コードに変更を加えます。


修正箇所はmeshのuvプロパティVector2型の配列を渡しているところです。

mesh.uv = new Vector2[] {
    new Vector2 (0.5f, 1f),
    new Vector2 (1f, 0),
    new Vector2 (0, 0),
};

これが何を指すかを説明していきます。

f:id:esakun:20151129172803p:plain

UV座標とは貼り付けるテクスチャの座標のことで、原点(0.0, 0.0)は画像の左下、右上が(1.0, 1.0)となり横がU座標、縦がV座標で、0.0〜1.0の範囲です。

先のuvプロパティに代入しているVector2型の配列は画像の三角形が丁度収まるようにUV座標を設定しています。

f:id:esakun:20151129174004p:plain

では、次のようなUV座標を代入してみるとどうなるでしょうか。

float texSize = 256f;
mesh.uv = new Vector2[] {
    new Vector2 (86f / texSize, 100f / texSize),
    new Vector2 (116f / texSize, 42f / texSize),
    new Vector2 (60f / texSize, 42f / texSize),
};

f:id:esakun:20151129174136p:plain

このようにUV座標で指定した部分がメッシュに描画されます。

まとめ

本記事では、以下の事をやってきました。

  1. 三角形メッシュを生成
  2. メッシュをカラーで描画
  3. UV座標を設定してテクスチャを描画する

個人的には、ほんの数行で三角形を描画できてしまったので、すごく簡単だなという印象です。

WebGLやDirectXをフルスクラッチで書くときには、頂点情報のバインド、テクスチャのロード処理、シェーダとのヒモ付などとてもとても面倒くさいのですが、Unityではそういった煩わしいことが一切なく三角形を描画できてしまうのは、繰り返しになりますがと言わざるを得ません。

あわせてどうぞ

その他の動的にメッシュを生成するシリーズ

Unity動的にメッシュを生成するシリーズ - 渋谷ほととぎす通信