내일배움캠프 Unity 69일차 TIL - 팀 9와 4분의 3 - 개발일지

Wooooo·2024년 2월 1일
0

내일배움캠프Unity

목록 보기
71/94

[오늘의 키워드]

절차적 맵 생성 방식을 도입했다.
새 게임을 시작할 때마다 새로운 맵을 랜덤으로 생성하진 않을 거지만, 자연스러운 지형 생성을 위해 도입했다.


[절차적 맵 생성]

펄린 노이즈란?

펄린 노이즈는 난수를 생성할 때, 인접한 부분끼리는 연속된 값으로 난수를 생성한다.
연속적인 난수 값을 생성하기 때문에 랜덤한 커브 그래프 비슷한 것이 나온다.

이 노이즈의 차원을 높이면, 지형의 Height Map으로 사용할 수 있다.

펄린 노이즈를 이용해 지형을 생성해보자.
중요한 점은, 나는 랜덤 생성을 원하는 것이 아니라 그럴싸한 지형을 원하는 것이기 때문에

펄린 노이즈의 속성값, 섬의 모양 등을 내 맘대로 커스터마이징 할 수 있도록 구현해야했다.

인스펙터 모습

펄린 노이즈 커스터마이징

펄린 노이즈를 인스펙터에서 커스터마이징 할 수 있도록 했다.

펄린 노이즈를 커스터마이징하는 방법은 다음과 같다.

  • 노이즈 생성 시 매개변수로 들어갈 x, z좌표값에 적용될 스케일
  • 노이즈를 몇 번 중첩할 지 결정하는 옥타브(Octaves).
  • 중첩 당 노이즈의 주파수(frequency) 배율을 결정하는 lacunarity
  • 중첩 당 노이즈의 진폭(amplitude) 배율을 결정하는 persistence
  • 의사 난수 seed. 같은 시드를 가졌다면 항상 같은 노이즈를 생성한다.

섬 모양 커스터마이징

Height Curve를 이용해서 섬 모양을 대략적으로 설정할 수 있도록 했다.
커브의 time이 0에 가까울 수록 섬의 중앙의 높이, 1에 가까울 수록 끄트머리의 높이이다.
위 이미지의 커브는 섬의 중앙에 계단 모양의 산이 생기도록 설정했다.

코드

    private IEnumerator GenerateHeightMap()
    {
        _heightMap = new float[_sizeX, _sizeZ];

        // 의사 난수 생성
        System.Random pseudoRandom = new(_seed.GetHashCode());
        float seedX = pseudoRandom.Next(0, 99999);
        float seedZ = pseudoRandom.Next(0, 99999);

        // Height Curve를 사용하기 위해 섬 길이 계산
        Vector2 center = new(_sizeX/2, _sizeZ/2);
        float radius = Mathf.Max(Vector2.Distance(center, new(_sizeX / 2, 0)), Vector2.Distance(center, new(0, _sizeZ / 2)));

        for (int x = 0; x < _sizeX; x++)
        {
            for (int z = 0; z < _sizeZ; z++) 
            {
                float amplitude = 1f;   // 진폭
                float frequency = 1f;   // 주파수
                float noiseHeight = 0f;

                // 옥타브만큼 노이즈 중첩
                for (int i = 0; i < _octaves; i++)
                {
                    float coordX = seedX + x * _noiseScale * frequency;
                    float coordZ = seedZ + z * _noiseScale * frequency;
                    float noise = Mathf.PerlinNoise(coordX, coordZ);
                    noiseHeight += noise * amplitude;
                    amplitude *= _persistence;
                    frequency *= _lacunarity;
                }

                // 계산된 펄린노이즈에 HeightCurve 높이 추가
                Vector2 pos = new(x, z);
                float t = Mathf.Clamp01(Vector2.Distance(pos, center) / radius);
                float curveHeight = _heightCurve.Evaluate(t) * _heightCurveScale;

                _heightMap[x, z] = noiseHeight + curveHeight;
            }
        }

        yield return null;
    }

구현 모습

추운 섬

중앙 섬

더운 섬


[TODO LIST]

슬라이드 블럭 배치

캐릭터들이 오르내릴 수 있는 슬라이드 블럭을 배치해야한다.

그런데 얘까지 절차적으로 생성할 방법? 쉽지 않음 ,,

우선은 마우스 클릭으로 레이캐스트를 쏴서 맞은 메시의 법선을 찾아와서 슬라이드 블럭을 배치하는 브러시 툴? 비슷한걸 만들어볼 생각이다.

생성 방식은 다음과 같다.

레이를 쏴서 맞은 메시의 법선을 찾는다.
그러면 생성할 슬라이드 블럭의 위치는 (레이를 맞은 블럭의 위치 + 법선벡터)이다.

슬라이드 블럭이 바라봐야할 방향 역시 법선벡터와 같다.

사용하지 않을 블럭 지우기?

현재 섬 3개의 블럭은 대략 100만개의 블럭을 가지고 있다.......

특히 산 안쪽에는 보이지 않을 블럭 데이터까지 수 십만 개 가지고 있다.
특히 산과 같이 높이가 있는 청크를 생성할 때 속도가 느려지는게 확연하게 보이기 때문에

데이터를 생성할 때 모든 면이 다 그려지지 않는 블럭을 지운다면? 로딩속도 개선이 될지도 ?

하지만 이러면 보여질 일이 없는 메시가 다시 그려질 수도 있는데, 이 부분은 추가 작업을 해야할 것 같다.


[참고 자료]

https://1217pgy.tistory.com/7
https://chipmunk.tistory.com/4?category=1011704

profile
game developer

0개의 댓글