【連載】Unity時代の3D入門 – 第3回「テクスチャを貼ってみた」

こんにちは、クライアントサイドエンジニアの矢野です。

第2回ではトーラス型の立体を描画しました。
第3回は、前回のモデルにテクスチャ(画像)を貼ってみようと思います。
テクスチャを貼るためには、モデルの各頂点にuv座標という情報を付加します。

uv座標とは

uv座標とは、テクスチャ上の点の位置を表すための座標です。
下図のようにテクスチャの左下を(0, 0)、右上を(1, 1)として座標を定義します。
例えば、画像の中央を表すuv座標は(0.5, 0.5)となります。

モデルにテクスチャを貼るときには、各頂点にこのuv座標を指定することで、その頂点にテクスチャのどの部分を割り当てるのかを指定します。

マテリアルの作成

実際にテクスチャを貼る前に、今回はマテリアルを作成します。
マテリアルの詳細は次回以降の記事で説明しますが、ここではひとまず、今回はモデルに陰をつけずにテクスチャの色だけを適用したいので作成する、という意図だけ認識しておいてください。

マテリアルを作成するためには、まずProjectビューで右クリックしてから Create > Material を選択して任意の名前を設定します。

次に作成したマテリアルを選択した状態で、インスペクタから Shader に Unlit > Texture を選択し、Base (RGB) と表記されている欄にテクスチャを設定します。

これでマテリアルの作成は完了です。

正方形に貼ってみる

それではまず正方形のモデルにテクスチャを貼ってみます。

まず、正方形の頂点座標と、それぞれの頂点に割り当てるuv座標を指定する必要があります。
これを表したものが下図です。

これをスクリプトで表すと次のようになります。

using UnityEngine;

public class TextureMappingRect : MonoBehaviour {

    [SerializeField]
    private Material _material;

    private Mesh _mesh;

    private Vector3[] _positions = new Vector3[]{ 
        new Vector3(-1, -1, 0),
        new Vector3(-1, 1, 0),
        new Vector3(1, -1, 0), 
        new Vector3(1, 1, 0)
    };

    private int[] _triangle = new int[]{ 0, 1, 2, 2, 1, 3 };

    private Vector3[] _normals = new Vector3[]{ 
        new Vector3(0, 0, -1),
        new Vector3(0, 0, -1),
        new Vector3(0, 0, -1),
        new Vector3(0, 0, -1)
    };

    // (1) uv座標の定義
    private Vector2[] _uvs = new Vector2[]{
        new Vector2(0, 0),
        new Vector2(0, 1),
        new Vector2(1, 0),
        new Vector2(1, 1),
    };

    private void Awake () {
        _mesh = new Mesh();

        _mesh.vertices = _positions;
        _mesh.triangles = _triangle;
        _mesh.normals = _normals;
        // (2) uv座標を適用
        _mesh.uv = _uvs;

        _mesh.RecalculateBounds();
    }

    private void Update () {
        Graphics.DrawMesh(_mesh, Vector3.zero, Quaternion.identity, _material, 0);
    }
}

これをGameObjectにアタッチし、インスペクタからMaterialに先ほど作成したマテリアルを参照させて再生すると

テクスチャが貼られたモデルが描画されました。

トーラスにテクスチャを貼る

次にトーラスにテクスチャを貼ってみます。
トーラスには次のテクスチャを使用します。

手順は正方形のときと同様で、まずはこのテクスチャを持つマテリアルを作成し、次にスクリプトでuv座標を定義します。
下記のスクリプトは、第2回で作成したものにuv座標周りの記述を追加したものです。

using System.Collections.Generic;
using UnityEngine;

public class TextureMappingTorus : MonoBehaviour {

    [SerializeField]
    private Material _material;

    private Mesh _mesh;

    void Awake () {
        var r1 = 3.0f;
        var r2 = 1.0f;
        var n = 20;

        _mesh = new Mesh();

        var vertices = new List<Vector3>();
        var triangles = new List<int>();
        var normals = new List<Vector3>();
        var uvs = new List<Vector2>();

        for (int i = 0; i <= n; i++) {
            var phi = Mathf.PI * 2.0f * i / n;
            var tr = Mathf.Cos(phi) * r2;
            var y = Mathf.Sin(phi) * r2;

            for (int j = 0; j <= n; j++) {
                var theta = 2.0f * Mathf.PI * j / n;
                var x = Mathf.Cos(theta) * (r1 + tr);
                var z = Mathf.Sin(theta) * (r1 + tr);

                vertices.Add(new Vector3(x, y, z));
                normals.Add(new Vector3(tr * Mathf.Cos(theta), y, tr * Mathf.Sin(theta)));

                // (1) uv座標を代入
                uvs.Add(new Vector2((float)j / (float)n, (float)i / (float)n));
            }
        }

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                var count = (n + 1) * j + i;
                triangles.Add(count);
                triangles.Add(count + n + 2);
                triangles.Add(count + 1);
                triangles.Add(count);
                triangles.Add(count + n + 1);
                triangles.Add(count + n + 2);
            }
        }

        _mesh.vertices = vertices.ToArray();
        _mesh.triangles = triangles.ToArray();
        _mesh.normals = normals.ToArray();

        // uv座標の適用
        _mesh.uv = uvs.ToArray();

        _mesh.RecalculateBounds();
    }

    void Update () {
        Graphics.DrawMesh(_mesh, Vector3.zero, Quaternion.identity, _material, 0);
    }
}

(1)でuv座標を計算し、 (2) でそれをMeshに代入しています。
今回は単純に、最初に作られた頂点のuv座標が (0, 0)、最後に作られた頂点のuv座標が (1, 1) となるように設定しています。

これをGameObjectにアタッチし、マテリアルを設定して再生すると、

テクスチャを貼られたトーラスが描画されました。

またわかりやすいように、モデルに一枚のテクスチャが貼られるイメージをアニメーションにしてみました。

まとめ

今回は、以下のことをやりました。

  • uv座標
  • マテリアルの作成
  • uv座標の指定、テクスチャの適用

今回までで、メッシュに基本的な描画の情報を与える流れの説明は完了しました。
次回からは、このようにして与えた情報が処理されていく部分、シェーダを見ていきます。

バックナンバー