유니티/3D 랜덤 맵

[Unity] 3D 랜덤 맵 - 2. 자연스러운 지형 생성

이름?없음 2024. 2. 21. 16:46
반응형

저번 글에서는 터레인을 이용하여 지형을 생성해 봤습니다

하지만 너무 부자연스러운 지형이 생성되는 문제가 있었습니다

그래서 이번 글에서는 저번 코드를 바탕으로 더 자연스럽게 지형이 생성되도록 해보겠습니다

반응형

우선 기존에 부자연스럽게 지형이 생성되는 문제를 해결하기 위해서는 Perline noise가 아닌 Fractal noise를 사용하여야 합니다

Fractal noise란? : 저주파 Perline noise와 고주파 Perline noise를 중첩하여 얻어낸 디테일한 노이즈

Perline noise
Fractal noise (출처 : AlexAyars)& nbsp;https://www.flickr.com/photos/aayars/4072756284

 

차이가 보이시나요? 그러면 이 Fractal noise를 생성하고 그것을 기반으로 지형을 생성하는 코드를 작성해 보도록 하겠습니다

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);

    }

    private void SetTerrain(float[,] noiseArr)
    {

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

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

    }


    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); // -1 ~ 1

                    frequency *= lacunarity;
                    amplitude *= gain;

                }

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

                    min = noiseArr[x, y];

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

                    max = noiseArr[x, y];

                }


            }

        }


        //중첩된 노이즈값을 0~1로 변환
        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;

    }


}

 

펄린 노이즈를 중첩한 후 역보간으로 0~1으로 변환해 주었습니다

역보간이란? : 2024.02.11 - [유니티/기타] - [Unity] Mathf.InverseLerp

 

[Unity] Mathf.InverseLerp

오늘은 InverseLerp함수에 관해 배워봅시다 일단 그전에 Lerp에 관한 설명을 보고 오시면 이해가 더 편할 겁니다 2024.02.11 - [유니티/기타] - [Unity] Lerp함수 [Unity] Lerp함수 오늘은 유니티의 Lerp 함수에

no-name-stroy.tistory.com

 

이렇게 코드를 수정하고 실행해 보시면?

확실히 더 디테일한 지형이 생성된 것을 확인할 수 있습니다

가까이서 보면 더 채감이 되실 겁니다

산?맥

 

하지만 지형의 색이 이런 식이면 안 되겠죠

다음 글에서는 지형에 텍스쳐를 입혀보도록 하겠습니다

반응형

'유니티 > 3D 랜덤 맵' 카테고리의 다른 글

[Unity] 3D 랜덤 맵 - 3. 지형 색칠  (0) 2024.02.21
[Unity] 3D 랜덤 맵 - 1. 지형 생성  (0) 2024.02.21