과제하다가 오랜만에 다시 작업해봤어
복잡한데 내 머리도 정리할 겸 적어보려고
밑 사진들은 전부 다 정확히 바이옴의 경계선 위에서 찍은 스크린샷.
바이옴마다 전부 다른 노이즈값을 사용하는것 치고 감쪽같지?
2D노이즈와 3D노이즈의 혼합인데, 3D는 주로 지형생성 자체에 쓰였고, 2D는 바이옴 및 추가 보정값을 구하는데 쓰였어.
우선 바이옴을 27개로 나누는 방법은 3개의 노이즈 함수를 이용해서, 각 노이즈 함수의 범위의 조합에 따라 바이옴을 나눠주면 돼.
노이즈함수 A,B,C(2D노이즈)가 있으면
A : 0.2, B 0.2, C 0.2 는 평지, A : 0.5, B 0.2, C 0.2 는 설원, A : 0.5, B 0.5, C 0.8은 숲 , 이런식으로.
그런데 이러면 바이옴의 경계선이 너무 단조로워서, 여기에 추가 노이즈값을 적용해서 굴곡진 경계면을 만들어봤는데 잘못 적용한건지 큰 효과는 없는 것 같아
A 대신 A + a, B 대신 B + a, C 대신 C + a를 사용했어.
여기서 내 C 노이즈 값은 높이를 담당하는 노이즈값이야.
바이옴이 결정되는 기준에 "높이"가 들어가기 때문에, 바이옴 사이의 높이차이를 구현하기가 쉬워.
산이랑 바다가 같은 높이에 존재하면 많이 이상하겠지? 그런 문제점을 해결해줄 수 있어.
이걸 설명하기 전에 3D 노이즈 함수로 원하는 높이를 기준으로 지형을 생성하는 법부터 설명할게.
n을 3D 노이즈 함수에서 나온 값이라고 할게. n은 -1~1사이의 값이야.
value = n * Range + 기준높이 - 현재 체크중인 블록의 높이
value > 0인 경우에 블록 설치, value <= 0인 경우에 공기 설치.
Range를 30으로 잡아보자. n * Range는 -30~30의 값이야.
기준높이를 기준으로 현재 체크중인 블록의 높이가 30 이상 낮다면 무조건 0보다 커져서 블록을 설치해.
(기준높이 - 체크높이 >= 30)이 되니깐 여기에 n*Range를 아무리 더해봤자 양수가 되잖아.
마찬가지로 체크중인 블록의 높이가 30 이상 높다면 무조건 0보다 작아져서 공기만 설치가 돼.
다시말해 기준높이를 기준으로 +-30만큼의 굴곡을 지닌 지형이 생성돼.
그런데 이게 끝이 아니야. 이렇게 마무리 지으면, 극적인 지형은 나타나지 않아.
아래로 내려갈수록 블록이 설치될 확률이 높고, 위로 올라갈수록 낮아져서 3D 노이즈의 특징을 제대로 살리기가 힘들어.
이런 지형
하나의 (x,z)좌표에서 y값을 내리면서 블록을 설치하는지 체크한다고 칠 때,
위에 적어둔 계산식에서 (체크하는 블록의 y값)을 최대한 기준높이와 유사하게 보정해주면 돼.
(체크하는 블록의 y값)이 기준높이와 일치할 때 3D노이즈 본연의 지형이 구현되거든.
예를 들면 기준높이가 50이고 체크하는 높이가 60이다, 이러면 체크하는 y값에 들어가는 변수를 대충 52정도로 넣어주면 되겠지.
이러면 최대한 많은 범위가 "기준높이"와 유사하게 되어 넓은 범위에 걸쳐서 3D노이즈 지형의 원형을 살릴수가 있어.
이제 "높이"를 고려한 바이옴 생성에 대해서
높이 노이즈 함수의 값이 1~2 사이면 바다, 2~3 사이면 숲, 3~4 사이면 산으로 설정해줬다고 치자.
이게 끝이야.
지형을 생성할 때 "기준높이"를 저 노이즈 함수의 값에 n을 곱한 값으로 설정하면 돼.
나는 50을 곱했기 때문에, 산은 대략 150 높이에 존재하고, 숲은 100, 바다는 50에 존재해.
여기서 한가지 문제점이 있었어. 아까 바이옴 노이즈함수를 이용할 때 C + a를 이용한다고 했잖아.
이렇게 되면 a의 범위만큼 지형의 높이가 울퉁불퉁해져서 이상해져. 그래서 바이옴 구분은 C+a로 하고, 높이값 구하는 함수는 C만 이용했어.
어차피 바이옴이 다르면 사용되는 지형생성 노이즈와 함수가 전혀 달라질거라 꽤 괜찮을 것 같아.
그런데 이러면 또 바이옴과 바이옴의 경계면의 높이가 항상 100, 150으로 일정해서 인위적인 느낌이 강하더라.
그래서 또다른 heightmap 노이즈(2D)를 이용해서 모든 (x,z)좌표의 "기준높이"를 구할때 여기에 이 heightmap의 값을 더해줬어.
연속적인 그래프 + 연속적인 그래프 = 연속적인 그래프.
여기까진 간단했고 이제 어려웠던 부분.
전혀 다른 노이즈값을 지닌 바이옴들을 어떻게 자연스럽게 연결시키는가.
바이옴이 다른 바이옴과 가까워질수록, 지형생성 함수의 n *Range의 값이 0에 가까워지면 돼.
모든 n*Range가 0이라면, 결국 "기준높이"를 2D heightmap으로 이용하는 상황과 같아지거든.
그리고 "기준높이"는 전체 월드에서 연속적인 값이니깐, 이어지겠지.
그런데 자연스럽게 전환하는게 힘들고, 아직도 개선해야 할 부분이 많아.
지형생성 함수의 n*Range를 n*Range* biomeMultiplier로 업그레이드 시켰어.
biomeMultiplier는 바이옴의 가장자리에 가까워질수록 0이되고, 중앙일수록 1이 되는 값이야.
이 값을 구하는건 간단해.
아까 노이즈함수 A,B,C를 다시 가져와볼게.
A,B,C의 값은 0~3 사이이고 0~1, 1~2, 2~3 으로 바이옴을 나눠.
(0~1 사이의 소수가 0.5에 가까울수록 1, 0 또는 1에 가까울수록 0을 반환하는 함수)에 A,B,C를 넣어서 나온 값들을 전부 곱한값이 일단 기본 multiplier야.
근데 이 값을 보정해주지 않으면, biomeMultiplier가 너무 낮게 설정되고, 지형의 중간부터 이미 평평하고, 지형의 끝에 갈수록 더 평평해져서 이상해져.
이번엔 아까의 보정과는 다르게
이런식으로 바이옴의 경계선에 다가가면 부드럽게 전환되지만, 그외의 부분에서는 최대한 1에 근접한 값으로 유지시켜주도록 해야 해.
바이옴의 중앙부분에서는 최대한 1에 가깝게, 그리고 가장자리로 가면 급격히 줄어들다가 부드럽게 옆 바이옴으로 전환되도록.
난 2차함수 4개를 이어붙였어.
변곡점이라고 하던가? 그 부분에 대한 위치를 조정하면서 적절한 값을 찾아야 하거든.
자 여기서 마지막 노이즈값.
저 변곡점의 위치를 노이즈값으로 변화를 줬어.
쉽게 말하면, 바이옴이 가장자리로 갈수록 급격히 높이가 조정되는 구간의 길이가 노이즈값에 의해 변화하는거야.
그리고 현재 내 지형은 5개의 다른 노이즈로 구성이 되는데, 가장 큰 영향을 끼치는 1번 노이즈와 나머지 2,3,4,5번 노이즈는 서로 다른 biomeMultiplier값을 이용해.
전체적인 지형(1)은 최대한 완만하게, 나머지 작은 굴곡(2,3,4,5)들은 경계선 근처에서도 좀 공격적으로 나타나게
(과거 사진)
바이옴이 경계선으로 올라갈 때, 이런 형태로 올라가지 않도록 조절해준거야.
버그가 난건지 살짝 의아한 부분이 있긴 있는데 아무튼,
이제 이런 양방향 경사면이 드물게 나타나고, 이런 현상의 길이가 짧고, 봐줄만 해.
이상한 부분은 나중에 다시 확인해봐야지.
이제 여기서 높이에 따라 Range의 값을 보정해줄 생각이야.
biomeHeight가 낮아질수록 Range의 아랫범위를 감소시키고 높아질수록 윗 범위를 감소시켜주도록.
이러면 좀 더 바이옴에 알맞는 높이로 지형이 생성되며 이런 현상이 많이 줄어들거야. 적어도 내 상상속에서는 그래.
사실 노이즈 함수는 여기 말고도 쓰인데가 꽤 있어.
내 블록은 총 4개의 레이어로 구성되어있어.
1. 맨윗블록(잔디 등)
2. 모래 또는 흙 같은 블록
3. 사암 등
4. 돌
이런식으로 되어있는데, 각 층의 높이값 역시 노이즈로 결정해.
계속 흙 층의 높이 등이 달라지도록.
진짜 힘든데 뿌듯하다.
자세히 구현할수록 그냥 노이즈 함수에 값을 넣으면 되는 단순한 문제가 아니더라.
이제 또 과제하러 감.
ㄷㄷㄷㄷ 차원이달라..
쌌다브로