Greedy Meshing과 Texture Atalas 같이쓰기
텍스쳐를 입혀봅시다!
목차
- 마인크래프트 같은 Voxel 게임에서 메쉬 최적화하기
- Greedy Meshing과 Texture Atalas 같이쓰기
- 마인크래프트 같은 Voxel 메쉬에 Ambient Occlusion 추가하기
문제점
UV가 정상적으로 적용된 모습
Greedy Meshing을 적용해서 최적화된 메쉬는 인접한 면들이 병합되었기 때문에 uv를 만들 때 고려해야할 점이 많습니다. 만약 큐브의 한쪽 면의 uv를 (0,0) ~ (1,1) 까지 정해 텍스쳐 전부를 그리는 상황에서는 문제가 되지 않습니다. 바로 위 이미지처럼 말이죠. 왜냐하면 그냥 단순히 uv를 병합된 면의 가로와 새로 길이만큼 늘리고, 텍스쳐의 Warp 모드를 Repeat으로 설정하면 됩니다.
UV는 정상이지만, 문제가 많아보인다
하지만 이렇게 할 경우에는 만든 복셀 메쉬를 그릴 때 텍스쳐를 복셀 종류마다 딱 한장의 텍스쳐만 쓸 수 있다는 단점이 있습니다. 물론 그것도 2d Texture Array를 이용하면 가능할 수 있겠지만, 여기서는 Texture Atlas를 사용하는 방법을 다루도록 하겠습니다.
Texture Atlas
공기, 풀, 흙, 돌
public enum VoxelType { Air, Grass, Dirt, Stone } // Voxel의 타입
public enum Direction { Right, Left, Top, Down, Front, Back } // 큐브의 Face 방향
본 글에서 사용할 텍스쳐 아틀라스입니다. 0부터 5까지는 위 코드에서 Direction
을 의미하고, VoxelType
과 같게 비어있는 이미지부터 Air, Grass, Dirt, Stone 순으로 배치하였습니다.
float4 uv = new float4
{
x = CubeUVs[i].x * width,
y = CubeUVs[i].y * height,
z = atlasPosition.x,
w = atlasPosition.y
};
uv
를 전달할 때는 병합되어 만들어진 면의 크기를 곱한 uv를 넘겨주고 나머지 z와 w에 Atlas
에서 사용할 이미지의 좌표를 저장합니다. 그럼 Shader에서 그 정보를 이용해 타일링을 해주는거죠.
MipMap 문제
MipMap문제 해결 전/후 비교
Shader에서 이를 구현하기 위해서는 uv를 모듈러 연산을 하거나 frac 연산을 이용해 타일링을 하게됩니다. 하지만 이는 MipMap이 작동할 때 문제가 되는데, 작게 생성된 MipMap텍스쳐의 가장자리에서 이웃 픽셀을 샘플링하게되어 위 이미지처럼 이음새가 생깁니다. 이를 해결하기 위해 tex2Dgrad
와 ddx
, ddy
를 이용해 텍스쳐를 샘플링할 때 GPU가 옳바른 Mip Level을 결정할 수 있도록 해줍니다.
결과
최종 결과