対称性のあるmeshを作る

#はじめに

Unityでスクリプトからmeshを作って　対称性のあるオブジェクトを描画しようとしてみた備忘録

環境：Unity 2020.3.12f1

# 対称なものをつくる
Quaternionであらかじめ
軸に対して対称となる回転系を用意しておく。

これに、中心から少し離れた位置にある座標を掛けることで、球面上のどこかの点をとるようになる。

うまく内側の球と外側の球の大きさや角度を調整すると
多面体や星形多面体などの対称性のある形が現れるはず。

# 流れ
まず一つ　
三角ポリゴンを描画し、
前後にミラーし、
上下にミラーし、

あと、X軸、Y軸に90度づつねじれた形に回転しつつ複製しています。


https://twitter.com/tatmos/status/1436555675128111115?s=20

# スクリプト

``` MakePolyhedron.cs
using System.Collections.Generic;
using UnityEngine;

public class MakePolyhedron : MonoBehaviour
{
    //  3軸対象
    readonly Quaternion[] _qs3S = {Quaternion.Euler(0, 0, 0), Quaternion.Euler(0, 90, 90), Quaternion.Euler(90, 0, 90)};

    //  前後対象
    readonly Quaternion[] _qfbs = {Quaternion.Euler(0, 0, 0), Quaternion.Euler(0, 180, 0)};

    //  上下対象
    readonly Quaternion[] _qtbts = {Quaternion.Euler(0, 0, 0), Quaternion.Euler(0, 0, 180)};

    private readonly List<Vector3> _vertices = new List<Vector3>();

    private Mesh _mesh;

    private void Start()
    {
        GetComponent<Renderer>().material.SetColor("_Color",
            new Color(Random.Range(0.25f, 0.85f), Random.Range(0.25f, 0.85f), Random.Range(0.25f, 0.85f)));

        _mesh = new Mesh();

        TriangleSetUp();

        var meshFilter = GetComponent<MeshFilter>();
        meshFilter.mesh = _mesh;
    }

    private void TriangleSetUp()
    {
        foreach (var qs3 in _qs3S)
        {
            foreach (var qfb in _qfbs)
            {
                foreach (var qtbt in _qtbts)
                {
                    for (int i = 0; i < 3; i++)
                    {
                        //  頂点を用意
                        _vertices.Add(Quaternion.Euler(Random.Range(0, 45), Random.Range(0, 45), Random.Range(0, 45)) *
                                      new Vector3(0, 1, 0));
                    }
                }
            }
        }

        //  頂点登録
        _mesh.SetVertices(_vertices);

        var triangles = new List<int>();

        for (int i = 0; i < _vertices.Count; i++)
        {
            triangles.Add(i);
        }

        _mesh.SetTriangles(triangles, 0);
    }


    private void Update()
    {
        TriangleSeed(1 + Mathf.Sin(Time.timeSinceLevelLoad), 1, 45 + Mathf.Sin(Time.timeSinceLevelLoad) * 45);
        _mesh.SetVertices(_vertices);
        _mesh.RecalculateBounds();
        _mesh.RecalculateNormals();
    }

    private void TriangleSeed(float l1, float l2, float fa)
    {
        var id = 0;

        foreach (var qs3 in _qs3S)
        {
            foreach (var qfb in _qfbs)
            {
                foreach (var qtbt in _qtbts)
                {
                    //  頂点を用意
                    _vertices[id++] = qtbt * qfb * qs3 * Quaternion.Euler(0, 0, 0) * new Vector3(0, l1, 0);
                    _vertices[id++] = qtbt * qfb * qs3 * Quaternion.Euler(90, fa, 0) * new Vector3(0, l2, 0);
                    _vertices[id++] = qtbt * qfb * qs3 * Quaternion.Euler(90, -fa, 0) * new Vector3(0, l2, 0);
                }
            }
        }
    }
}
```

# Mesh描画のためのコンポーネント
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96808/300f0219-fcfe-c221-d744-db5e3fb0688b.png)

MeshFilterとMeshRenererが必要なようです。


# ちょっと複製の仕方を変えてみる

https://twitter.com/tatmos/status/1436573763437359106?s=20

``` .cs
    //  前後対象 -> ４回回転対称
    readonly Quaternion[] _qfbs = {Quaternion.Euler(0, 0, 0), Quaternion.Euler(0, 90, 0), Quaternion.Euler(0, 180, 0), Quaternion.Euler(0, 270, 0)};
```