본문 바로가기
개발/Unity

유니티 - 절차적 메시로 정다각뿔, 원뿔 그리기 (Make Regular Pyramids, Cone with Procedural Mesh)

by 피로물든딸기 2022. 11. 6.
반응형

Unity 전체 링크

 

참고 - 정다각기둥, 원기둥 만들기

 

절차적 메시를 이용하여 정다각형, 원을 만들었으니 정다각뿔, 정N각뿔을 만들어보자.

정사면체를 만드는 방법에서 높이를 조절할 수 있도록 변경하고 코드를 확장하면 된다.

 

먼저 정다각형의 triangles 코드의 순서를 아래와 같이 바꾼다.

삼각형이 N개 더 추가되므로 triangles의 크기가 3 * N개 추가된다.

시계 방향으로 생성한 mesh를 반시계 방향으로 만들어 아래에서 보이도록 한다.

    triangles = new int[3 * polygon + 3 * polygon];
    for (int i = 0; i < polygon - 1; i++)
    {
        triangles[i * 3] = 0;
        triangles[i * 3 + 1] = i + 2;
        triangles[i * 3 + 2] = i + 1;
    }

    triangles[3 * polygon - 3] = 0;
    triangles[3 * polygon - 2] = 1;
    triangles[3 * polygon - 1] = polygon;

 

높이도 조절하도록 추가한다.

참고로 높이의 절반이 오브젝트의 기준점이 된다.

    public float height = 1.0f;

    void OnValidate()
    {
        if (mesh == null) return;

        if (size > 0 || offset.magnitude > 0 || polygon >= 3 || height > 0)
        {
            setMeshData(size, polygon);
            createProceduralMesh();
        }
    }

 

높이를 정하는 꼭지점이 하나 추가되면서 삼각형이 N개 더 추가되므로 3 * N개의 정점을 추가한다.

그리고 높이의 중심이 기준이 되도록 y값도 수정한다.

    vertices = new Vector3[polygon + 1 + (3 * polygon)];

    vertices[0] = new Vector3(0, -height / 2.0f, 0) + offset;
    for (int i = 1; i <= polygon; i++)
    {
        float angle = -i * (Mathf.PI * 2.0f) / polygon;

        vertices[i]
            = (new Vector3(Mathf.Cos(angle), -height / 2.0f, Mathf.Sin(angle)) * size) + offset;
    }

 

그리고 y 좌표는 size에 영향을 받으면 안되므로, size를 x, z 축에만 곱하도록 수정한다.

    vertices[i]
        = (new Vector3(Mathf.Cos(angle) * size, -height / 2.0f, Mathf.Sin(angle) * size ) ) + offset;

 

 

밑면의 정다각형 외에 나머지 삼각형은 vertices 순서 그대로 triangles에 넣어주면 편하다.

정N각형을 만들면서 triangles의 index가 3 * N - 1이 되었으므로 tIdx를 3 * N부터 시작하면서 값을 넣는다.

    int tIdx = 3 * polygon;
    Vector3 point = new Vector3(0, height / 2.0f, 0) + offset;
    for (int i = 1; i <= polygon - 1; i++)
    {
        vertices[polygon + 1 + 3 * i - 3] = point;
        vertices[polygon + 1 + 3 * i - 2] = vertices[i];
        vertices[polygon + 1 + 3 * i - 1] = vertices[i + 1];

        triangles[tIdx++] = polygon + 1 + 3 * i - 3;
        triangles[tIdx++] = polygon + 1 + 3 * i - 2;
        triangles[tIdx++] = polygon + 1 + 3 * i - 1;
    }

    vertices[polygon + 1 + (3 * polygon) - 1 - 2] = point;
    vertices[polygon + 1 + (3 * polygon) - 1 - 1] = vertices[polygon];
    vertices[polygon + 1 + (3 * polygon) - 1 - 0] = vertices[1];

    triangles[tIdx++] = polygon + 1 + (3 * polygon) - 1 - 2;
    triangles[tIdx++] = polygon + 1 + (3 * polygon) - 1 - 1;
    triangles[tIdx++] = polygon + 1 + (3 * polygon) - 1 - 0;

 

게임을 실행하고 설정을 변경하면 정다각뿔 → 원뿔을 만들어볼 수 있다.

 

Mesh Renderer를 끄면 아래와 같이 Mesh가 만들어지는 것을 볼 수 있다.

 

전체 코드는 다음과 같다.

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

[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class ProceduralRegularPyramids : MonoBehaviour
{
    public int polygon = 3;
    public float size = 1.0f;
    public float height = 1.0f;
    public Vector3 offset = new Vector3(0, 0, 0);

    Mesh mesh;
    Vector3[] vertices;
    int[] triangles;

    void OnValidate()
    {
        if (mesh == null) return;

        if (size > 0 || offset.magnitude > 0 || polygon >= 3 || height > 0)
        {
            setMeshData(size, polygon);
            createProceduralMesh();
        }
    }

    void Start()
    {
        mesh = GetComponent<MeshFilter>().mesh;

        setMeshData(size, polygon);
        createProceduralMesh();
    }

    void setMeshData(float size, int polygon)
    {
        vertices = new Vector3[polygon + 1 + (3 * polygon)];

        vertices[0] = new Vector3(0, -height / 2.0f, 0) + offset;
        for (int i = 1; i <= polygon; i++)
        {
            float angle = -i * (Mathf.PI * 2.0f) / polygon;

            vertices[i]
                = (new Vector3(Mathf.Cos(angle) * size, -height / 2.0f, Mathf.Sin(angle) * size ) ) + offset;
        }

        triangles = new int[3 * polygon + 3 * polygon];
        for (int i = 0; i < polygon - 1; i++)
        {
            triangles[i * 3] = 0;
            triangles[i * 3 + 1] = i + 2;
            triangles[i * 3 + 2] = i + 1;
        }

        triangles[3 * polygon - 3] = 0;
        triangles[3 * polygon - 2] = 1;
        triangles[3 * polygon - 1] = polygon;

        /* -------------------------------------------------------- */

        int tIdx = 3 * polygon;
        Vector3 point = new Vector3(0, height / 2.0f, 0) + offset;
        for (int i = 1; i <= polygon - 1; i++)
        {
            vertices[polygon + 1 + 3 * i - 3] = point;
            vertices[polygon + 1 + 3 * i - 2] = vertices[i];
            vertices[polygon + 1 + 3 * i - 1] = vertices[i + 1];

            triangles[tIdx++] = polygon + 1 + 3 * i - 3;
            triangles[tIdx++] = polygon + 1 + 3 * i - 2;
            triangles[tIdx++] = polygon + 1 + 3 * i - 1;
        }

        vertices[polygon + 1 + (3 * polygon) - 1 - 2] = point;
        vertices[polygon + 1 + (3 * polygon) - 1 - 1] = vertices[polygon];
        vertices[polygon + 1 + (3 * polygon) - 1 - 0] = vertices[1];

        triangles[tIdx++] = polygon + 1 + (3 * polygon) - 1 - 2;
        triangles[tIdx++] = polygon + 1 + (3 * polygon) - 1 - 1;
        triangles[tIdx++] = polygon + 1 + (3 * polygon) - 1 - 0;
    }

    void createProceduralMesh()
    {
        mesh.Clear();
        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.RecalculateNormals();

        Destroy(this.GetComponent<MeshCollider>());
        this.gameObject.AddComponent<MeshCollider>();
    }
}

 

참고

- 위의 경우 polygon이 많을 때 불필요한 정점이 상대적으로 많아진다. 

- 따라서 정점을 필요한 만큼만 만들고 triangles로 배치한다.

 

Unity Plus:

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Unity Pro:

 

Unity Pro

The complete solutions for professionals to create and operate.

unity.com

 

Unity 프리미엄 학습:

 

Unity Learn

Advance your Unity skills with live sessions and over 750 hours of on-demand learning content designed for creators at every skill level.

unity.com

반응형

댓글