2017年4月21日

Unity 動的にメッシュを作成する ~テクスチャ編~


スクリプトからメッシュを作成する方法について、悪戦苦闘しながらの解説その4。生成したメッシュに色をつけます…


※このページの内容の動作確認にはUnity5.3を使用しています。
前回はパーリンノイズを使って自然っぽく見える地形を作りました。今回は、テクスチャを動的に作成し、頂点の高さに応じて色をつけてみたいと思います。

Gradient Editorで色を設定

まずは、どの高さでどの色にするかという情報を扱う変数を用意しましょう。高さと色を組み合わせた配列的なものを独自に用意してもいいのですが、今回は簡単にするためGradientで対応してみます。

public Gradient meshColorGradient;

このような変数を宣言すると、インスペクタ上でGradient Editorを使って色のグラデーションが設定できるようになります。こんな感じです。


パーティクルの設定とかでは見たことがあったんですが、普通にスクリプトからも使えるんですね。ゲージの左端が0%(0.0)、右端が100%(1.0)になるので、低い位置で表示したい色(水とか)は左側、高い位置の色(山とか)は右側に配置しておきます。実はキーが最大で8個までしか登録できないっぽいのが難点なのですが、まあ今回は簡易ということでこれでよしとします…

UVを計算

さて、次に準備するのはUVです。UVというのはテクスチャをメッシュのどの部分に対応させるかを示すもので、これがないとテクスチャを用意しても「どう貼り付けたらいいの?」ってことになります。というわけで、頂点情報(vertices) と三角形情報(triangles)を計算したあとの部分に以下のコードを追加します。

Vector2[] uvs = new Vector2[size * size];
for (int z = 0; z < size; z++) {
 for (int x = 0; x < size; x++) {
  uvs[z * size + x] = new Vector2(x / (float)size, z / (float)size);
 }
}

まずUVのサイズはメッシュの頂点数と同じでいいのでsize*sizeでOK。あとは開始地点が(0, 0)になり、最終地点が(1, 1)になるように、実際のメッシュの頂点と位置関係を対応させながら座標をあてはめていきます。テクスチャの左下部分が(0, 0)、テクスチャの中心が(0.5, 0.5)、テクスチャの右上が(1, 1)とそれぞれ対応し、これでテクスチャ全体が地表に貼り付けられるようになりました。

あとはメッシュの作成時に

Mesh mesh = new Mesh();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.uv = uvs;

…とUVの設定を追加するだけです。

テクスチャを作成

ではいよいよテクスチャを作成しメッシュに貼り付けます。

public float minHeight;
public float maxHeight;
Texture2D CreateTexture(Vector3[] vertices)
{
 Color[] colorMap = new Color[vertices.Length];
 for (int i = 0; i < vertices.Length; i++) {
  float percent = Mathf.InverseLerp(minHeight, maxHeight, vertices[i].y);
  colorMap[i] = meshColorGradient.Evaluate(percent);
 }
 Texture2D texture = new Texture2D(size, size);

 texture.SetPixels(colorMap);
 texture.Apply();

 return texture;
}

まずminHeightとmaxHeightという2つの変数を追加。地形の最も低い位置と最も高い位置を手動で設定できるようにしました。

次に、地形の頂点情報を受け取ってテクスチャを返すCreateTextureというメソッドを作成しました。それぞれの頂点のY座標に応じてcolorMap配列に色の情報を格納していきます。途中で出てくるMathf.InverseLerp(a, b, value)は「aを0、bを1とした場合、valueは0~1のどんな値になるか」を調べるメソッドです。たとえばもしMathf.InverseLerp(2, 16, 9)であれば、9は2と16のちょうど中間なので0.5を返します。次の行でその値をmeshColorGradient.Evaluateに渡し、Gradient Editorで設定した色を取得するというわけです。

あとはTexture2Dを新規に作成。さっき求めた色情報の配列をtexture.SetPixels(colorMap)というふうに指定するだけで、テクスチャの各ピクセルに色を塗ってくれます。めっちゃ便利!最後はtexture.Apply()でその変更を適用&確定するという流れです。

テクスチャをマテリアルに設定

ではいよいよラストです。MeshRendererにマテリアルを設定する部分で、同時にテクスチャも設定しちゃいます。

meshRenderer.sharedMaterial.mainTexture = CreateTexture(vertices);

さっき作ったCreateTextureメソッドを呼び出しテクスチャを取得、そのままマテリアルに渡しています。これで頂点座標が色に変換され、色の情報からテクスチャが作成され、そのテクスチャがマテリアルに適用されました。



やっと完成。なかなか綺麗ですな。次回はさらにテクスチャの手直しをしたいと思います。

<次回> テクスチャ手直し編

0 件のコメント:

コメントを投稿