simplestarの技術ブログ

目的を書いて、思想と試行、結果と考察、そして具体的な手段を記録します。

Unity:テクスチャ付き六角柱メッシュをスクリプトだけで構築しました

AIに身体性を与えるためのマイクロワールドの構築2です。

まずは三角形を、頂点データを構築することによって、表示してみたいと思います。

参考にしたページはこちら
www.shibuya24.info

ただ三角形を表示するのも芸がないので、六角柱を作ってみました。

f:id:simplestar_tech:20171007220344j:plain

作成コードは次の通り

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

[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshFilter))]
public class CreateMeshScript : MonoBehaviour {

    [SerializeField]
    private Material _mat;

    // Use this for initialization
    void Start () {

        var mesh = new Mesh();
        float root3 = Mathf.Sqrt(3f);

        Vector3[] positions = new Vector3[] {
            new Vector3 (0f, 1f, 0f),
            new Vector3 (0f, 1f, 2f),
            new Vector3 (root3, 1f, 1f),
            new Vector3 (root3, 1f, -1f),
            new Vector3 (0f, 1f, -2f),
            new Vector3 (-root3, 1f, -1f),
            new Vector3 (-root3, 1f, 1f),

            new Vector3 (0f, -1f, 0f),
            new Vector3 (0f, -1f, 2f),
            new Vector3 (root3, -1f, 1f),
            new Vector3 (root3, -1f, -1f),
            new Vector3 (0f, -1f, -2f),
            new Vector3 (-root3, -1f, -1f),
            new Vector3 (-root3, -1f, 1f),
        };
        mesh.vertices = new Vector3[] {
            // 天板
            positions[0], positions[ 1], positions[ 2], positions[ 0], positions[ 2], positions[ 3], positions[ 0], positions[ 3], positions[ 4], positions[ 0], positions[ 4], positions[ 5], positions[ 0], positions[ 5], positions[ 6], positions[ 0], positions[ 6], positions[ 1], 
            // 底板
            positions[7], positions[ 9], positions[ 8], positions[ 7], positions[10], positions[ 9], positions[ 7], positions[11], positions[10], positions[ 7], positions[12], positions[11], positions[ 7], positions[13], positions[12], positions[ 7], positions[ 8], positions[13], 

            // 側面
            positions[1], positions[ 8], positions[ 2], 
            positions[2], positions[ 9], positions[ 3], 
            positions[3], positions[10], positions[ 4], 
            positions[4], positions[11], positions[ 5], 
            positions[5], positions[12], positions[ 6],
            positions[6], positions[13], positions[ 1], 
            // 側面2
            positions[1], positions[13], positions[ 8],
            positions[2], positions[ 8], positions[ 9],
            positions[3], positions[ 9], positions[10],
            positions[4], positions[10], positions[11],
            positions[5], positions[11], positions[12],
            positions[6], positions[12], positions[13]           
        };

        int[] triangles = new int[mesh.vertices.Length];
        for (int i = 0; i < mesh.vertices.Length; i++)
        {
            triangles[i] = i;
        }
        mesh.triangles = triangles;
        mesh.RecalculateNormals();

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

        var renderer = GetComponent<MeshRenderer>();
        renderer.material = _mat;

    }

    // Update is called once per frame
    void Update () {
		
	}
}

続いて、次のテクスチャを貼ります。
f:id:simplestar_tech:20171008153753p:plain

ということで貼りました。

f:id:simplestar_tech:20171008153828j:plain

うまく貼られているようですね。

この UV 設定まで行うコードを次に示します。

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

[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshFilter))]
public class CreateMeshScript : MonoBehaviour {

    [SerializeField]
    private Material _mat;

    // Use this for initialization
    void Start() {

        var mesh = new Mesh();
        float root3 = Mathf.Sqrt(3f);

        Vector3[] positions = new Vector3[] {
            new Vector3 (0f, 1f, 0f),
            new Vector3 (0f, 1f, 2f),
            new Vector3 (root3, 1f, 1f),
            new Vector3 (root3, 1f, -1f),
            new Vector3 (0f, 1f, -2f),
            new Vector3 (-root3, 1f, -1f),
            new Vector3 (-root3, 1f, 1f),

            new Vector3 (0f, -1f, 0f),
            new Vector3 (0f, -1f, 2f),
            new Vector3 (root3, -1f, 1f),
            new Vector3 (root3, -1f, -1f),
            new Vector3 (0f, -1f, -2f),
            new Vector3 (-root3, -1f, -1f),
            new Vector3 (-root3, -1f, 1f),
        };
        mesh.vertices = new Vector3[] {
            // 天板
            positions[ 0], positions[ 1], positions[ 2], // 1 
            positions[ 0], positions[ 2], positions[ 3], // 2
            positions[ 0], positions[ 3], positions[ 4], // 3
            positions[ 0], positions[ 4], positions[ 5], // 4
            positions[ 0], positions[ 5], positions[ 6], // 5
            positions[ 0], positions[ 6], positions[ 1], // 6 
            // 底板
            positions[ 7], positions[ 9], positions[ 8], // 1
            positions[ 7], positions[10], positions[ 9], // 2
            positions[ 7], positions[11], positions[10], // 3
            positions[ 7], positions[12], positions[11], // 4
            positions[ 7], positions[13], positions[12], // 5
            positions[ 7], positions[ 8], positions[13], // 6 

            // 側面
            positions[1], positions[ 8], positions[ 2], // 1天
            positions[2], positions[ 8], positions[ 9], // 1底

            positions[2], positions[ 9], positions[ 3], // 2天
            positions[3], positions[ 9], positions[10], // 2底

            positions[3], positions[10], positions[ 4], // 3天
            positions[4], positions[10], positions[11], // 3底

            positions[4], positions[11], positions[ 5], // 4天
            positions[5], positions[11], positions[12], // 4底

            positions[5], positions[12], positions[ 6], // 5天
            positions[6], positions[12], positions[13], // 5底

            positions[6], positions[13], positions[ 1], // 6天
            positions[1], positions[13], positions[ 8], // 6底
 
        };

        int[] triangles = new int[mesh.vertices.Length];
        for (int i = 0; i < mesh.vertices.Length; i++)
        {
            triangles[i] = i;
        }
        mesh.triangles = triangles;

        Vector2[] uvSources = new Vector2[]
        {
            // 天板
            new Vector2 (0.25f, 0.25f),
            new Vector2 (0.25f, 0.50f),
            new Vector2 (0.50f, 0.375f),
            new Vector2 (0.50f, 0.125f),
            new Vector2 (0.25f, 0.0f),
            new Vector2 (0.00f, 0.125f),
            new Vector2 (0.00f, 0.375f),
            // 底板
            new Vector2 (0.75f, 0.25f),
            new Vector2 (0.75f, 0.50f),
            new Vector2 (0.75f, 0.0f),
            new Vector2 (1.00f, 0.125f),
            new Vector2 (1.00f, 0.375f),
            // 側面x6
            new Vector2 (0.25f, 1.00f),
            new Vector2 (0.25f, 0.75f),
            new Vector2 (0.00f, 1.00f),
            new Vector2 (0.50f, 1.00f),
            new Vector2 (0.50f, 0.75f),
            new Vector2 (0.75f, 1.00f),
            new Vector2 (0.75f, 0.75f),
            new Vector2 (0.00f, 0.75f),
            new Vector2 (0.50f, 0.50f),
            new Vector2 (0.00f, 0.50f),
        };

        Vector2[] uvs = new Vector2[] {
            // 天板
            uvSources[0], uvSources[1], uvSources[2], // 1
            uvSources[0], uvSources[2], uvSources[3], // 2
            uvSources[0], uvSources[3], uvSources[4], // 3
            uvSources[0], uvSources[4], uvSources[5], // 4
            uvSources[0], uvSources[5], uvSources[6], // 5
            uvSources[0], uvSources[6], uvSources[1], // 6

            // 底板
            uvSources[7], uvSources[2], uvSources[8],   // 1
            uvSources[7], uvSources[3], uvSources[2],   // 2
            uvSources[7], uvSources[9], uvSources[3],   // 3
            uvSources[7], uvSources[10], uvSources[9],  // 4
            uvSources[7], uvSources[11], uvSources[10], // 5
            uvSources[7], uvSources[8], uvSources[11],  // 6

            // 側面
            uvSources[12], uvSources[13], uvSources[14], // 1天
            uvSources[14], uvSources[13], uvSources[19], // 1底

            // 2
            uvSources[15], uvSources[16], uvSources[12], // 2天
            uvSources[12], uvSources[16], uvSources[13], // 2底
            // 3
            uvSources[17], uvSources[18], uvSources[15], // 3天
            uvSources[15], uvSources[18], uvSources[16], // 3底
            // 4
            uvSources[13], uvSources[1], uvSources[19], // 4天
            uvSources[19], uvSources[1], uvSources[21], // 4底
            // 5
            uvSources[16], uvSources[20], uvSources[13], // 5天
            uvSources[13], uvSources[20], uvSources[1],  // 5底
            // 6
            uvSources[18], uvSources[8], uvSources[16], // 6天
            uvSources[16], uvSources[8], uvSources[20], // 6底
            
        };
        mesh.uv = uvs;

        mesh.RecalculateNormals();

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

        var renderer = GetComponent<MeshRenderer>();
        renderer.material = _mat;

    }

    // Update is called once per frame
    void Update () {
		
	}
}

このコードの見どころは、バッファに追加する頂点情報を六角柱の各面ごとに切り分けられている点です。
つまり、マップ生成を自動化したときに、表示する必要のない面の情報をそぎ落としながら、一つのメッシュとして…

あれ、複数のマテリアルが設定されている時は、メッシュを分けないといけないのかな…
次は、複数マテリアルを利用するメッシュの自動生成について調べていきます。

ちょっと調べた感じ…
なるほど、

Mesh.subMeshCount = 2;             // 2つのSubMeshを格納できるように指定.
Mesh.SetTriangles(triangles0, 0);  // 0番目のSubMeshを格納.
Mesh.SetTriangles(triangles1, 1);  // 1番目のSubMeshを格納.

という感じにして、materials にマテリアルを設定するのか