🐡

UnityでShader始めてみた No.2 四角形・多角形

2022/11/25に公開

前置き

前回は動的に三角形を生成し、シェーダーを適用してみました。
今回は四角形を作成し、汎用性を高めるためにN角形でも適用できるようにしてみます。
シェーダーと言うよりC#プログラムメインですね。

四角形

動的に四角形のメッシュを生成しています。

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

[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshFilter))]
public class DynamicCreateSquare : MonoBehaviour
{
    private void Start()
    {
        var mesh = new Mesh();

        // 頂点座標の配列
        mesh.vertices = new Vector3[]
        {
            new Vector3(-1f,  1f, 0),
            new Vector3( 1f,  1f, 0),
            new Vector3( 1f, -1f, 0),
            new Vector3(-1f, -1f, 0),
        };

        // インデックス配列
        mesh.triangles = new int[]
        {
            0, 1, 2,
            0, 2, 3
        };

        // 頂点に色情報を割り当てる
        mesh.SetColors(new Color[] { Color.red, Color.green, Color.blue, Color.cyan });

        // メッシュをセット
        var filter = GetComponent<MeshFilter>();
        filter.sharedMesh = mesh;

        // シェーダーセット
        var renderer = GetComponent<MeshRenderer>();
        renderer.material = new Material(Shader.Find("Unlit/Color"));
    }
}

頂点座標の配列

四角形の頂点は4つなので、それぞれの座標を指定します。

square

インデックス配列

四角形を作っていますが、メッシュは三角形が2個の組み合わせでできています。

square2

そのため、インデックス配列では2つの三角形を作る頂点を指定します。
つまり0, 1, 20, 2, 3 です。
時計回りに指定しないと、表側と認識されずに表示されないので注意です。

シェーダーを適用して実行した画面がこちら。
square3
頂点の色の境目で三角形が2個あるのが見えますね。

多角形

このまま正五角形、正六角形...と座標を指定しても良いのですが、プログラムで賢く実装してみます。
必要な値は、頂点座標インデックス配列の2つです。

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

[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshFilter))]
public class DynamicCreatePolygon : MonoBehaviour
{
    [Header("頂点の数")] 
    public int vertexNum = 5;

    Color[] colors = { Color.red, Color.blue, Color.green, Color.yellow, Color.cyan, Color.magenta };

    private void Start()
    {
        Vector3[] vertexPosition = new Vector3[vertexNum + 1];      // 頂点座標の配列
        int[] indexArray = new int[3 * vertexNum];                  // インデックス配列
        Color[] vertexColor = new Color[vertexNum + 1];                 // 頂点色配列
        float rotationAngle = 2 * Mathf.PI / vertexNum;             // 回転角

        var mesh = new Mesh();

        // 頂点座標
        for (int i = 0; i < vertexNum; i++)
        {
            vertexPosition[i + 1] = new Vector3(Mathf.Sin(i * rotationAngle), Mathf.Cos(i * rotationAngle), 0);
        }

        // インデックス配列
        for (int i = 0; i < vertexNum; i++)
        {
            indexArray[3 * i] = 0;
            indexArray[3 * i + 1] = i + 1;
            if (i+2 != vertexNum+1)
            {
                indexArray[3 * i + 2] = i + 2;
            }
            else
            {
                indexArray[3 * i + 2] = 1;
            }
        }

        // 頂点の色を決める
        for (int i = 0; i < vertexColor.Length; i++)
        {
            vertexColor[i] = colors[Random.Range(0, colors.Length)];
        }

        mesh.vertices = vertexPosition;
        mesh.triangles = indexArray;
        mesh.colors = vertexColor;

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

        var renderer = GetComponent<MeshRenderer>();
        renderer.material = new Material(Shader.Find("Unlit/Color"));
    }
}

頂点座標の配列

三角形のとき、頂点から頂点へは120度回転しています。
四角形のときは90度、五角形のときは72度です。
つまり、ラジアンに直すと

\frac{2\pi}{N}

ずつ回転していることになります。
これをあらかじめ計算しておきます。

インデックス配列

正五角形のとき頂点は5個ありますが、三角形で構成するには6個必要です。

No2_2

指定する3つの頂点のうち、最初は必ず0番目となります。

  • 0, 1, 2
  • 0, 2, 3
  • 0, 3, 4
  • 0, 4, 5
  • 0, 5, 1

の5つを指定すれば良さそうです。
これをプログラムに書きますが、0, 5, 1のときだけ、if文で場合分けして実装しました。

シェーダーをつけて実行します。
右から順に正五角形, 正六角形, 正十角形です。
No.2_3
良い感じに表示できました!

参考リンク

【Unity】四角形のポリゴンを作ってテクスチャを貼る
Unityでプロシージャルモデリング (三角形・四角形・正多角形)

Discussion