본문 바로가기
개발/Unity

유니티 - 절차적 메시로 간단한 지형 만들기 (Make Simple Terrain with Procedural Mesh)

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

Unity 전체 링크

 

절차적 메시로 N x M 크기의 평면에서 y 값을 적절히 주면 아래와 같이 간단한 지형을 만들 수 있다.

 

(x, z) 좌표에 대해 y가 적절히 지형스러운 값이 되도록 값을 넣어주면 된다.

이때 사용되는 y값이 noise가 되고 PerlinNoise를 사용하면 간단하다.

 

이전 코드에서 ny를 추가하고 Mathf.PerlineNoise를 이용하면 된다.

    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, ny, nz;

            nx = sx + x * cellSize;
            ny = sy + Mathf.PerlinNoise(x * xNoise, z * zNoise) * noiseHeight;
            nz = sz - z * cellSize;

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

 

PerlineNoise는 0 ~ 1 사이의 float을 return하므로, 지형의 높이를 변경하기 위해 noiseHeight 만큼 곱한다.

 

전체 코드는 다음과 같다.

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;

    public float xNoise = 0.5f;
    public float zNoise = 0.5f;
    public float noiseHeight = 1.0f;

    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, ny, nz;

                nx = sx + x * cellSize;
                ny = sy + Mathf.PerlinNoise(x * xNoise, z * zNoise) * noiseHeight;
                nz = sz - z * cellSize;

                vertices[vIdx++] = new Vector3(nx, ny, 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

반응형

댓글