마인크래프트 같은 Voxel 게임에서 메쉬 최적화하기
Voxel을 최적화해봅시다
목차
- 마인크래프트 같은 Voxel 게임에서 메쉬 최적화하기
- Greedy Meshing과 Texture Atalas 같이쓰기
- 마인크래프트 같은 Voxel 메쉬에 Ambient Occlusion 추가하기
바보 같은 방법
무척 낭비가 심합니다!
먼저 32*32*32 크기의 청크가 있고, 모든 복셀이 비어있지 않다고 합시다. 이때 마인크래프트 같은 메쉬를 생성하기 위한 가장 쉽고 편한 방법은 각 복셀을 순회하면서 복셀당 6면의 큐브를 만드는 것이죠.
큐브는 삼각형이 12개씩 필요하니 총 Vertex와 Index수는 24, 36개로, 최악의 경우에 모든 청크에 대해서 Mesh를 만들면 786,432개의 Vertex와 1,179,648개의 Index가 필요하게 됩니다. 보통 한번 맵을 생성할 때 150개 정도 청크를 만들게 되는데, Editor 상에서 아무것도 하지 않고 Mesh만 생성해놓은 상태에서 25FPS가 나왔습니다. 쉽게 구현한 것에 비해 매우 행복하지 못할 결과죠.
보이지 않은 면 Culling
더 좋아질 수 있어요!
각 복셀을 순회하면서 면을 만들 때, 인접한 복셀이 존재한다면 그 면은 어디에서 봐도 보이지 않습니다. 물론 인접한 복셀이 투명하지 않다는 가정이 있어야겠지요. 아무튼 면을 만들 때 인접한 복셀이 있는지, 그 인접한 복셀은 투명하지 않은지 검사해서 만약 그렇다면 그냥 건너뛰면 삼각형의 수를 줄일 수 있습니다.
사실 저 청크는 하나의 거대한 큐브라고 생각할 수 있습니다. 그럼 아직도 불필요한 삼각형들이 존재한다는 사실을 알 수 있죠. 이를 해결하기 위해서 Greedy Meshing 방법을 사용하겠습니다.
Greedy Meshing
이 경우에는 최적의 Mesh입니다
각 복셀을 순회하면서 6개의 면을 추가하는 것이 아닌, 6 방향(X-, X+, Y-, Y+, Z-, Z+)을 순회하면서 인접한 Quad를 서로 병합하는 방법이죠. 일종에 2D 단면에 대해서 병합할 수 있는(Voxel의 Type이 같은 등) 면을 서로 합치는 알고리즘입니다. 이 글에서 알고리즘을 자세하게 설명하진 않겠습니다. 한 면에대한 Greedy Meshing은 이전 글 Marching Squares - Part 3 | Optimization에서 다루었으니 참고하시면 좋습니다.
Y축에 대해서만 Greedy Meshing
이런 변형도 가능합니다
2D 단면에 대해서 X, Y 두 축으로 Quad를 병합하는 작업은 조금 시간이 걸릴 수 있습니다. 따라서 알고리즘을 조금 변형해 한 축에 대해서(여기에서는 Y축)만 Quad를 병합할 수도 있죠. 이때는 메쉬를 만드는 시간이 Culling보다는 느리지만, Greedy Meshing보다는 빠르게 됩니다.
결과
Culling과 Greedy Meshing 비교
위와 같은 Scene을 구성해놓고 결과를 비교해보았습니다.