본문 바로가기
개발/Unity

유니티 - 절차적 메시로 N x M 평면 만들기 (Make N x M Plane with Procedural Mesh)

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

Unity 전체 링크

 

참고 - 절차적 메시로 지형 만들기

 

평면을 하나 만들고 와이어프레임만 보면 10 x 10 크기의 평면인 것을 알 수 있다.

 

여기서는 N x M 크기의 평면을 절차적 메시로 만들어보자.


10 x 10 평면은 정점이 11 x 11 = 121개다.

따라서 width x height의 정점은 (width + 1) x (height + 1)개다.

그리고 삼각형의 개수는 10 x 10 평면인 경우 200개이므로, 필요한 triangles의 크기는 600개이다.

즉 triangles의 size는 width * height * 6가 된다.

    vertices = new Vector3[(width + 1) * (height + 1)];
    triangles = new int[width * height * 6];

 

이제 N x M 평면에서 시작 좌표를 찾아보자.

 

위의 그림대로라면 (sx, sy, sz)는 아래와 같다. 

그리드의 크기(= cellSize)도 미리 고려하였다.

    float sx = offset.x - width / 2.0f * cellSize;
    float sy = offset.y;
    float sz = offset.z + height / 2.0f * cellSize;

 

vertices 좌표는 다음과 같이 구한다. 

    int vIdx = 0;
    for(int z = 0; z <= height; z++)
    {
        for(int x = 0; x <= width; x++)
        {
            float nx, nz;

            nx = sx + x * cellSize;
            nz = sz - z * cellSize;

            vertices[vIdx++] = new Vector3(nx, sy, nz);
        }
    }

 

그림으로 보면 아래의 순서대로 vertices를 저장하였다.

 

이제 triangles를 채워보자. (width = N)

첫번째 Grid가 N개가 첫 줄에 모두 생성되고 이 때의 순서는 0 ~ N - 1이다. 

그리고 다음 Grid는 N번째 사각형이다.

 

삼각형은 아래의 vertex를 시계방향으로 넣는다.

 

코드로 정리하면 다음과 같다.

점 1개가 정해지면(= vIdx) 나머지 3개의 점은 자동으로 정해진다.

다음 줄은 (width + 1)개 만큼 차이가 나기 때문에 width + 1이 더해진다.

    vIdx = 0;
    int tIdx = 0;
    for (int z = 0; z < height; z++)
    {
        for (int x = 0; x < width; x++)
        {
            triangles[tIdx++] = vIdx;
            triangles[tIdx++] = vIdx + 1;
            triangles[tIdx++] = vIdx + (width + 1);

            triangles[tIdx++] = vIdx + (width + 1);
            triangles[tIdx++] = vIdx + 1;
            triangles[tIdx++] = vIdx + (width + 1) + 1;

            vIdx++;
        }
        vIdx++;
    }

 

빈 오브젝트에 Mesh Filter, Renderer, Default-Material, ProceduralPlane.cs를 추가하고 게임을 실행하자.

 

설정을 변경하면 아래와 같이 원하는 크기, offset, cellSize대로 평면을 만들 수 있다.

 

최종 코드는 다음과 같다.

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

[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class ProceduralPlane : MonoBehaviour
{
    Mesh mesh;
    Vector3[] vertices;
    int[] triangles;

    public float cellSize = 1;
    public Vector3 offset;
    public int width, height;

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

        if(offset != Vector3.zero || width > 0 || height > 0 || cellSize > 0)
        {
            setMeshData();
            createProceduralMesh();
        }
    }

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

    void setMeshData()
    {
        vertices = new Vector3[(width + 1) * (height + 1)];
        triangles = new int[width * height * 6];

        float sx = offset.x - width / 2.0f * cellSize;
        float sy = offset.y;
        float sz = offset.z + height / 2.0f * cellSize;

        int vIdx = 0;
        for(int z = 0; z <= height; z++)
        {
            for(int x = 0; x <= width; x++)
            {
                float nx, nz;

                nx = sx + x * cellSize;
                nz = sz - z * cellSize;

                vertices[vIdx++] = new Vector3(nx, sy, nz);
            }
        }

        vIdx = 0;
        int tIdx = 0;
        for (int z = 0; z < height; z++)
        {
            for (int x = 0; x < width; x++)
            {
                triangles[tIdx++] = vIdx;
                triangles[tIdx++] = vIdx + 1;
                triangles[tIdx++] = vIdx + (width + 1);

                triangles[tIdx++] = vIdx + (width + 1);
                triangles[tIdx++] = vIdx + 1;
                triangles[tIdx++] = vIdx + (width + 1) + 1;

                vIdx++;
            }
            vIdx++;
        }
    }

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

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

 

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

반응형

댓글