LoginSignup
2
2

More than 5 years have passed since last update.

Unityでプロシージャルモデリング (球)

Last updated at Posted at 2018-07-15

Unityでメッシュをスクリプトでプロシージャルに生成する方法について何回かに分けて書いていきます。

今回は球を作ってみます。

sphere_01.PNG

Sphere.cs
using UnityEngine;

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Sphere : MonoBehaviour
{
    [SerializeField] private int thetaSegments = 5;
    [SerializeField] private int phiSegments = 8;

    private void Awake()
    {
        Mesh mesh = new Mesh();
        GetComponent<MeshFilter>().mesh = mesh;

        Vector3[] vertices = new Vector3[2 + (thetaSegments - 1) * phiSegments];
        int[] triangles = new int[(phiSegments) * 2 * 3 + (thetaSegments - 2) * phiSegments * 2 * 3];

        float thetaStep = Mathf.PI / thetaSegments;
        float phiStep = Mathf.PI * 2.0f / phiSegments;
        int vi = 0;
        int ti = 0;

        vertices[vi++] = new Vector3(0, -1, 0);
        for (int hi = 1;  hi < thetaSegments; hi++)
        {
            float theta = Mathf.PI - hi * thetaStep;
            for (int pi = 0; pi < phiSegments; pi++)
            {
                float phi = pi * phiStep;
                vertices[vi++] = new Vector3(Mathf.Sin(theta) * Mathf.Cos(phi), Mathf.Cos(theta), Mathf.Sin(theta) * Mathf.Sin(phi));
            }
        }
        vertices[vi++] = new Vector3(0, 1, 0);

        for (int pi = 0; pi < phiSegments; pi++)
        {
            triangles[ti++] = 0;
            triangles[ti++] = pi + 1;
            triangles[ti++] = pi != phiSegments - 1 ? (pi + 1) + 1 : 1;
        }
        for (int hi = 0; hi < thetaSegments - 2; hi++)
        {
            for (int pi = 0; pi < phiSegments; pi++)
            {
                int pj = pi != phiSegments - 1 ? pi + 1 : 0;
                int v00 = pi + hi * phiSegments + 1;
                int v10 = pj + hi * phiSegments + 1;
                int v01 = pi + (hi + 1) * phiSegments + 1;
                int v11 = pj + (hi + 1) * phiSegments + 1;
                ti = MakeQuad(triangles, ti, v00, v10, v01, v11);
            }
        }
        for (int pi = 0; pi < phiSegments; pi++)
        {
            triangles[ti++] = vertices.Length - 1;
            triangles[ti++] = (pi != phiSegments - 1 ? pi + 1 : 0) + (thetaSegments - 2) * phiSegments + 1;
            triangles[ti++] = pi + (thetaSegments - 2) * phiSegments + 1;
        }

        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.RecalculateNormals();
    }

    private int MakeQuad(int[] triangles, int ti, int v00, int v10, int v01, int v11)
    {
        triangles[ti] = v00;
        triangles[ti + 1] = triangles[ti + 5] = v01;
        triangles[ti + 2] = triangles[ti + 4] = v10;
        triangles[ti + 3] = v11;
        return ti + 6;
    }
}

今回作成する球では、球面座標系での2つの角度θφをそれぞれthetaSegmentsphiSegmentsの値で分割するように頂点を配置しています。

球は以下のような三角形で構成されています(分割数はデフォルト値)。頂点の配置などは異なりますが、以前説明した円柱と同じように底面、側面、上面の三角形を順々に定義していきます。

sphere_02.PNG

以下は球を見上げたときの頂点と三角形の構成を表しています。球の底面部分は円柱の底面部分と同じように定義しています。

sphere_ex_bottom.png

球の側面部分も円柱と同様に平面の水平方向の端を繋げたように構成しています。

sphere_ex_side.png

以下は球を上から見下ろしたときの頂点と三角形の構成で、球の上面も円柱の上面と同じように定義しています。

sphere_ex_top.png

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2