유니티/3D 랜덤 맵

[Unity] 3D 랜덤 맵 - 3. 지형 색칠

이름?없음 2024. 2. 21. 17:43
반응형

저번 글에서는 지형을 자연스럽게 생성해 보았습니다

하지만 지형의 텍스쳐가 하나뿐이라 부자연스럽게 보이는 문제가 있었습니다

이번 글에서는 지형에 텍스쳐를 입혀 자연스럽게 보이도록 해보겠습니다

반응형

우선 터레인레이어를 추가해 주셔야 합니다

저는 4개만 추가해 주었습니다

이 레이어들에는 번호가 부여되는데요 왼쪽부터 0, 1, 2, 3 이런 식으로 부여됩니다

 

이제 설정한 터레인 레이어를 기반으로 지형을 색칠해 주는 코드를 작성해 보겠습니다

using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;

public class EX : MonoBehaviour
{

    [Header("타일맵 관련")]
    [SerializeField] private Terrain terrain;
    [Space]
    [Header("값 관련")]
    [SerializeField] private float mapScale = 0.003f;
    [SerializeField] private int mapSize = 4096;
    [SerializeField] private int depth = 600;
    [SerializeField] private int octaves = 6;

    private float seed;

    private async void Start()
    {

        seed = Random.Range(0, 10000f);

        var noiseArr = await Task.Run(GenerateNoise);

        SetTerrain(noiseArr);
        DrawTerrain(noiseArr);

    }

    private void SetTerrain(float[,] noiseArr)
    {

        terrain.terrainData.size = new Vector3(mapSize, depth, mapSize);

        terrain.terrainData.SetHeights(0, 0, noiseArr);

    }

    private void DrawTerrain(float[,] noiseArr)
    {

        //알파맵 가져오기
        //1, 2차원 위치
        //3차원 스플랫맵 택스쳐
        var arr = terrain.terrainData.GetAlphamaps(0, 0, terrain.terrainData.alphamapWidth, terrain.terrainData.alphamapHeight);

        for (int y = 0; y < terrain.terrainData.alphamapHeight; y++)
        {
            for (int x = 0; x < terrain.terrainData.alphamapWidth; x++)
            {

                for(int t = 0; t < terrain.terrainData.alphamapLayers; t++)
                {

                    //높이에 맞게 설정
                    arr[x, y, t] = GetIndex(noiseArr[x, y]) == t ? 1 : 0;

                }

            }
        }

        //설정
        terrain.terrainData.SetAlphamaps(0, 0, arr);

    }

    //터레인 레이어 번호를 반환
    private int GetIndex(float value)
    {

        switch (value)
        {

            case <= 0.3f: return 0;
            case <= 0.35f: return 1;
            case <= 0.4f: return 2;
            default: return 3;

        }

    }



    private float[,] GenerateNoise()
    {

        float[,] noiseArr = new float[mapSize, mapSize];
        float min = float.MaxValue, max = float.MinValue;

        for (int x = 0; x < mapSize; x++)
        {

            for (int y = 0; y < mapSize; y++)
            {

                float lacunarity = 2.0f;
                float gain = 0.5f;

                float amplitude = 0.5f;
                float frequency = 1f;

                for (int i = 0; i < octaves; i++)
                {

                    noiseArr[x, y] += amplitude * (Mathf.PerlinNoise(
                        seed + (x * mapScale * frequency),
                        seed + (y * mapScale * frequency)) * 2 - 1);

                    frequency *= lacunarity;
                    amplitude *= gain;

                }

                if (noiseArr[x, y] < min)
                {

                    min = noiseArr[x, y];

                }
                else if (noiseArr[x, y] > max)
                {

                    max = noiseArr[x, y];

                }


            }

        }

        for (int x = 0; x < mapSize; x++)
        {

            for (int y = 0; y < mapSize; y++)
            {

                noiseArr[x, y] = Mathf.InverseLerp(min, max, noiseArr[x, y]);

            }

        }

        return noiseArr;

    }


}

이제 실행해 보시면?

지형이 잘 색칠되는 것을 확인하실 수 있습니다

저는 예쁘라고 물도 넣어봤어요

 

이것을 응용하면 다양한 지형을 만들 수 있을 것입니다

이상으로 3D 랜덤 맵을 마치도록 하겠습니다

반응형