
산, 절벽, 그리고 동굴: 절차적 생성 (Procedural Generation)을 위한 Perlin Noise 사용 가이드
요약
이 가이드는 자연스러운 지형 생성을 위한 절차적 생성(Procedural Generation) 기술과 그 핵심인 Perlin noise의 원리를 설명합니다. 단순한 무작위 배열과 달리 Perlin noise가 어떻게 부드럽고 연속적인 기울기를 형성하여 산, 절벽, 동굴과 같은 복잡한 지형을 구현하는지 다룹니다.
핵심 포인트
- 절차적 생성은 알고리즘을 통해 수동 디자인 없이 자연스러운 텍스처와 오브젝트를 만드는 기술입니다.
- Perlin noise는 완전한 무작위성과 달리 부드럽고 연속적인 값을 제공하여 자연스러운 지형 형성에 적합합니다.
- Ken Perlin의 알고리즘은 무작위 숫자 배열 대신 무작위 벡터의 좌표 그리드를 사용하여 구현됩니다.
- 노이즈의 스케일과 미세 조정을 통해 산맥, 초원, 바다 등 다양한 지형을 시뮬레이션할 수 있습니다.
산, 절벽, 그리고 동굴: 절차적 생성 (Procedural Generation)을 위한 Perlin Noise 사용 가이드
2025년 2월 27일
6분 읽기
업데이트: 3일 전
절차적 생성 (Procedural generation)은 어디에나 있습니다. 아마 여러분도 인지하지 못한 채 접해 보았을 것입니다. 게임 속 세상에 완만한 언덕, 험준한 절벽, 그리고 구불구불한 동굴 시스템을 부여하는 것이 바로 이것입니다. 그리고 그 중심에는 Perlin noise가 있습니다. 이는 완전히 무작위는 아닌, 특별한 종류의 무작위성입니다. 필요한 곳에서는 부드럽고, 원하는 대로 거칠게 만들 수 있으며, 끝없이 커스터마이징이 가능합니다.
하지만 절차적 생성 (Procedural generation)이란 정확히 무엇일까요? 간단히 말해, 모든 세부 사항을 수동으로 디자인하는 대신 알고리즘을 사용하여 자연스럽게 보이는 텍스처와 오브젝트를 만드는 방법입니다.
Minecraft를 예로 들어보겠습니다. 새로운 월드를 불러올 때마다 여러분은 완전히 독특한 지형을 마주하게 됩니다. 이 월드들은 손으로 직접 디자인된 것이 아닙니다 (불쌍한 인턴들을 생각해 보세요). 대신, 절차적 생성 (Procedural generation)을 사용하여 구축됩니다. 전통적인 수작업 환경과 달리, 절차적 생성 (Procedural generation)을 사용하면 단 몇 줄의 코드만으로도 거대하고 복잡한 지형을 즉석에서 만들어낼 수 있습니다.
이 가이드에서는 Perlin noise가 어떻게 작동하는지 분석하고, 처음부터 직접 구현하며, 우리가 원하는 방식대로 지형을 형성하기 위해 이를 미세 조정하는 방법을 다룰 것입니다. 이 아이디어를 한 단계 더 발전시켜 지하 동굴 시스템을 설계하기 시작하는 방법까지 확인하려면 끝까지 읽어주세요.
이 프로젝트의 모든 코드는 GitHub에서 확인할 수 있습니다. 직접 시도해 보세요!
자, 노이즈를 만들어 봅시다!
믿기 힘들겠지만, 이것이 절차적으로 생성된 지형의 시작입니다. 이것은 노이즈 (noise)의 그래픽 표현으로, 0과 1 사이에서 무작위로 생성된 값들의 배열입니다. 뚜렷한 패턴이 없으며, 현재로서는 지형 지도와 전혀 닮지 않았습니다. 이는 무작위적이고 불연속적(discontinuous)이어서, 부드러운 지형을 생성하는 데는 별로 도움이 되지 않을 것입니다. 우리가 정말로 필요한 것은 다음과 같은 형태입니다:
이것이 Perlin noise입니다. 여전히 꽤 무작위적으로 보이고 예측 불가능하게 동작하지만, 자연스러운 지형 (terrain)을 생성하는 데 훨씬 더 유용하게 만들어 줄 부드럽고 연속적인 기울기 (gradient)를 가지고 있습니다.
여기에서의 채색은 눈 덮인 산봉우리, 초록빛 초원, 그리고 짙은 푸른색 바다가 있는 지형도 (topological map)의 탑다운 뷰 (top-down view)를 시뮬레이션합니다. 아마 3차원으로 시각화하는 것이 더 쉬울 것입니다:
아직 완전한 웅장한 산맥은 아니지만, 올바른 방향으로 나아가는 단계입니다. 따라서 이를 좀 더 산맥 같은 것으로 수정하기 전에, 이 부드러운 노이즈 (noise)가 어떻게 생성되는지 살펴보겠습니다.
고마워요, Ken!
그의 1985년 논문 (아래 링크됨)에서, Ken Perlin은 그의 노이즈 생성 알고리즘을 설명합니다. 그는 컴퓨터 그래픽 (computer graphics)을 위한 무작위 자연 질감 (natural textures)을 생성하는 몇 가지 사용 사례를 개괄합니다.
이 알고리즘에는 다양한 구현 방식이 있지만, 핵심 아이디어는 다음과 같습니다…
무작위 숫자 배열 (array)로 시작하는 대신, 우리는 무작위 벡터 (vector)의 좌표 그리드 (coordinate grid)로 시작할 것입니다.
Perlin noise는 픽셀 단위 (per-pixel basis)로 생성되므로, 출력물의 각 픽셀을 가져와 벡터 그리드에 매핑 (map)할 것입니다.
여기에서 첫 번째 파라미터 (parameter)인 스케일 (scale)을 도입합니다. 스케일은 픽셀이 벡터 그리드에 매핑되는 방식을 수정할 수 있게 해줍니다. 나중에 살펴보겠지만, 이는 지형의 전반적인 부드러움에 영향을 미칩니다.
지형의 크기와 원하는 출력물의 크기에 따라, 모든 픽셀 좌표를 매핑할 수 있을 만큼 충분히 큰지 확인하기 위해 그리드를 확장하거나 타일링 (tile)해야 할 수도 있습니다.
벡터 그리드 상의 한 픽셀 좌표를 플로팅 (plotting)하면, 이제 해당 지점에서 각 경계 모서리 (bounding corners, 아래 초록색으로 표시됨)까지의 거리 벡터 (distance vector)를 계산할 수 있습니다.
각 기울기 벡터 (gradient vector)와 그에 대응하는 거리 벡터의 내적 (dot product)을 구하면, 각 모서리에 대해 하나씩 총 4개의 숫자가 생성됩니다.
이 픽셀에 대한 최종 노이즈 값 (noise value)을 계산하기 위해, 네 개의 모서리 값 사이를 먼저 가로 방향으로, 그다음 세로 방향으로 보간 (interpolate)합니다. 이를 통해 특정 모서리 벡터에 더 가까운 점이 다른 벡터들보다 해당 벡터의 영향을 더 많이 받도록 보장합니다.
모든 노이즈 값이 생성되면, 마지막 단계는 값들을 [0, 1] 범위 내로 정규화 (normalise)하는 것입니다. 이렇게 하면 이전에 보았던 것과 같은 노이즈 맵 (noise map)을 얻을 수 있습니다.
울퉁불퉁한 굴곡 추가하기
스케일 (scale) 파라미터를 변경하면 지형의 매끄러움이 달라집니다.
- 더 큰 스케일 값은 고주파 (high-frequency) 파형을 생성하여 결과물이 상당히 거칠게 보이게 합니다.
- 더 작은 스케일 값은 저주파 (lower frequency) 파형을 생성하여 더 매끄러운 외관을 갖게 합니다.
스케일은 픽셀 값을 벡터 그리드 (vector grid)에 매핑하는 것입니다. 스케일이 작을 때, 우리는 그리드의 각 사각형에 많은 값을 매핑하며, 이는 매끄러운 곡선을 만들어냅니다. 스케일이 클 때는 더 큰 간격으로 벡터 그리드를 샘플링하므로, 노이즈 값에서 더 급격한 변화가 나타날 수 있습니다.
이제 모든 것이 하나로 합쳐집니다
지형의 디테일과 복잡성을 높이기 위해 프랙탈 브라운 운동 (Fractal Brownian Motion)이라고 알려진 기술을 사용할 수 있습니다. 이 방법은 서로 다른 주파수 (frequency)와 진폭 (amplitude)을 가진 여러 층의 Perlin noise를 결합하여 더 자연스러운 결과를 만들어내는 방식입니다.
이러한 노이즈의 층을 옥타브 (octaves)라고 부릅니다.
옥타브 (Octaves)
지형에 점점 더 미세한 수준의 디테일을 추가함으로써 옥타브의 수를 늘린다고 생각할 수 있습니다. 하나의 옥타브로는 넓은 형태를 추가하고, 두 번째 옥타브로는 약간 더 작은 특징들을 추가하지만, 6번째 또는 8번째 옥타브에 이르면 지도의 표면에 아주 작은 결점이나 세부 사항만을 추가하게 됩니다.
또한 우리는 두 가지 파라미터를 더 사용하여 옥타브의 속성과 이들을 결합하는 방식을 변경할 수 있습니다: 지속성 (persistence)과 간극성 (lacunarity)입니다.
지속성 (Persistence)
지속성은 최종 결과에 대한 각 옥타브의 기여도를 변경합니다. 첫 번째 옥타브의 진폭 (amplitude)을 1로 시작하여, 각 반복 (iteration)마다 진폭에 지속성 스케일 인자 (persistence scale factor)를 곱합니다.
예를 들어, persistence (지속성)가 0.5라면, 첫 번째 octave (옥타브)의 100%를 가져오고, 50%로 축소된 두 번째 octave를 더하며, 그다음은 25%로 축소된 것을 더하는 식으로 진행합니다. 각 연속적인 octave는 최종 결과에 점점 더 적은 영향을 미칩니다.
이는 octave의 주파수 (frequency)가 증가하여 점점 더 거친 지형을 생성하는 것과 일치하지만, 완전히 새로운 산을 만들기보다는 표면에 작은 굴곡들을 추가하는 역할을 합니다.
여기서 낮은 persistence와 높은 persistence를 가진 2개의 octave가 결합된 예시를 보여줍니다.
높은 persistence 모델은 높은 주파수의 두 번째 octave에 의해 더 큰 영향을 받아, 지면에서 튀어나온 크고 들쭉날쭉한 봉우리들이 생성됩니다.
대조적으로, 낮은 persistence 모델은 두 번째 octave의 영향이 더 작기 때문에 지형 전체에 훨씬 작은 흠집들만이 나타납니다.
Lacunarity (틈새성)
우리가 변경할 수 있는 또 다른 파라미터 (parameter)는 lacunarity (틈새성)입니다. 이는 octave 사이의 스케일 (scale) 변화율을 의미합니다.
아래 예시에서는 4개의 octave와 0.25의 persistence를 사용합니다. 왼쪽 모델은 lacunarity가 2.0이므로 각 octave마다 스케일이 두 배가 되는 반면, 오른쪽 모델은 4.0의 값을 사용하여 각 octave마다 스케일이 네 배가 됩니다.
보시다시피, 최종 결과물은 전체적인 형태는 동일하지만, 높은 lacunarity 모델은 작은 특징들의 주파수가 훨씬 더 높습니다.
이 파라미터는 다른 파라미터들보다 미묘하지만, 지형의 질감을 변경하는 데 유용합니다.
제가 너무 흥분한 것 같군요…
Fractal Brownian Motion (프랙탈 브라운 운동)을 넘어, 우리는 지형 지도를 커스텀하기 위해 추가적인 변형들을 적용할 수 있습니다…
습도 수준과 바이옴 (Biomes)
Perlin noise를 지형의 높이 이외의 다른 것들을 표현하는 데 사용할 수 있습니다. 이 경우에는 환경의 습도 수준 (moisture levels)을 표현하는 데 사용하겠습니다. 고도와 습도 수준을 결합하면, 각 좌표를 서로 다른 바이옴 (biome)으로 분류하고 그에 따라 색상을 입힐 수 있습니다.
Radial Dropoff (방사형 낙차)
우리는 또한 노이즈 맵 (noise maps)에 함수를 적용하여 지형을 다양한 모양으로 조작할 수 있습니다.
이 예제에서는 산의 중심에서 좌표가 멀어질수록 값이 감소하는 이차 함수 (quadratic function)를 노이즈 값에 적용합니다. 그 결과, 바다 위로 솟아오른 높은 섬 형태의 산이 만들어집니다.
사용자 정의 함수 (Custom Functions)
하지만 단순히 이차 함수에만 국한되지는 않습니다. 멋지고 복잡한 다항식 (polynomial expression)을 가져와 우리의 값에 적용할 수도 있습니다.
한 가지 유의해야 할 점은 정의역 [0, 1] 내에서 함수의 그래프가 어떤 모양을 갖느냐 하는 것입니다. 함수가 노이즈 값을 합리적인 범위를 벗어나는 값으로 매핑하지 않도록 확인해야 합니다. 아래의 예제는 모든 값을 [0, 1] 범위 내로 유지하면서도 흥미로운 결과물을 만들어냅니다.
그 후, 이 함수를 조정하여 지형의 서로 다른 특징들을 과장하거나 억제하도록 맞춤 설정할 수 있습니다.
또한 Perlin noise 알고리즘을 2차원 이상의 차원, 예를 들어... 3차원으로 구현할 수도 있습니다!
3D 노이즈의 단일 옥타브 (octave)를 가져와 결과에 임계값 (threshold)을 적용하고, 몇 가지 미세 조정과 시각화 마법을 더하면, 결과물이 지하 동굴 시스템처럼 보이기 시작합니다.
Perlin noise를 몇 가지 영리하게 적용하는 것만으로도 산, 바다, 그리고 미로 같은 동굴 시스템까지 만들어낼 수 있습니다. 스케일 (scale), 지속성 (persistence), 그리고 간극도 (lacunarity)와 같은 파라미터를 조정함으로써 지형의 구조를 정밀하게 제어할 수 있으며, 여러 개의 옥타브를 레이어링함으로써 깊이와 복잡성을 더할 수 있습니다.
그리고 이것은 시작일 뿐입니다. 생물군계 (biome) 분류, 습도 (moisture levels), 그리고 3D 모델의 도입과 같은 추가적인 개선을 통해 절차적 생성 (procedural generation)을 더욱 확장할 수 있습니다. 게임 세계를 제작하든 생성 예술 (generative art)을 실험하든, 노이즈의 힘은 오직 당신의 상상력에 의해서만 제한될 뿐입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 HN Game Dev의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기