복셀 에디팅 팁
다신 안볼줄 알았는데.... -_- 요즘들어 다시 복셀(voxel) 에디팅에 대해 잠시 본 바.... 이 기회에 제가 이짓하면서 배운 교훈들을 짧게(정말?) 공유해볼까 합니다. 저번에 썼던 "혼합가능한 RGBM" 글 과는 달리 여기에 나열한 모든 정보/fact 들은 이미 온라인에 다 널려있는 내용입니다. 그냥 그 모든 내용들을 모아 제 의견을 약간 곁들인게 전부입니다.
1. isosurface부터 이해하세요
복셀 데이터를 주무르는 가장 실용적인 방법은 각 복셀마다 iso 값을 대입하는 겁니다. 다른 방법도 시도해봤는데요(물론 제가 발명해낸 기괴한 방법도 한번 시도해봤죠 -_-) 대부분 별로더라구요. 단점들이 있어요. 결국엔 iso 값으로부터 메쉬를 다시 생성해내는게 가장 실용적이고 메모리 친화적인 방법인거 같습니다. iso surface extraction에 대해 설명하는 무수한 논문이 있으나 정작 isosurface가 뭔지를 쉽게 설명하는 자료는 흔치 않더라구요.
여기 저기 뒤진 끝이 이 튜토리얼을 찾았습니다. 설명도 잘해놨구요. isosurface의 개념을 익히는데는 최고인듯 싶습니다. (물론 영어입니다... 이 글도 영문 블로그에 썻다가 한글로 번역하는 놈이기 때문에.. 혹시라도 괜찮은 한글자료 가지고 계신분은 공유좀 부탁 -_-a)
또한 3D Coat의 개발자가 매우 친절하게도 3D Coat에서 사용하는 복셀 데이터의 포맷을 공개해놨습니다. 이 데이터 구조를 들여다보는 것만으로도 복셀 에디팅에 대해 상당히 많은걸 배울 수 있습니다.
복셀 편집에는 큰 관심이 없고 그대신 임시 복셀 데이터로부터 절차적(procedurally)으로 거대한 지형(terrain)을 만드는게 목적이시라면 VoxelFarm inc의 블로그를 읽어보세요. 이 분 정말 천재더라구요. (실제 한번 만나도 봤습니다. 몬트리올 살때 -_-)
2. 복셀데이터는 "간접적" 으로만 변경할 수 있습니다
볼륨 데이터를 표현하기 위해 iso 값을 사용하게 되면 복셀 데이터를 변경할 수 있는 유일한 방법은 iso 값을 변경하는 것입니다. 이 연산들은 간단한 수학인데요. 각 iso 값을 증감하거나 이웃간의 값을 평균내는 등입니다. 물론 distance 함수를 직접 계산해서 새로운 isosurface 모양을 꾸겨넣을 순 있지요. (이 distance 함수에 대해서는 위에 링크를 걸어둔 튜토리얼을 참고해 주세요.)
iso 값과 최종 메쉬의 모양과는 1:1 관계가 없습니다. 즉 "이 edge를 0.2미터 오른쪽으로 늘리고 싶어. 그러니 복셀 값을 0.752로 바꿔야지!"라는 말을 할수가 없어요. 다시 말하면 최종 모양을 세밀하게 조절할 방법이 없습니다. 복셀의 밀도(density)를 아주 높이 올려도 (예: 1센치당 복셀 하나) 역시 마찬가지입니다. 이게 바로 제가 간접적으로만 복셀을 편집할 수 있다고 한 이유죠.
매우 뾰쪽한 edge를 가진 메쉬를 생성하는 새로운 알고리듬들도 있긴 합니다. 하지만 이 방법들은 복셀 편집을 위해 만들어진게 아닙니다. (자세한건 다음 섹션에서....)
3. 전통적인 마칭 큐브(marching cube)면 충분합니다
방금 말씀드렸듯이 iso데이터에서 메쉬를 생성하는 새로운 리서치들이 있습니다. 특히 Cubical Marching Square와 Efficient Voxel Octree가 꽤 주목할만한 리서치들인데요.
CMS는 매우 날카로운 edge를 생성할 수 있습니다. 단, 한가지 조건이 있습니다. 폴리곤 데이터로부터 iso값을 capture해야만 하지요. 이 방법은 큐브 표면에서 각 폴리곤 edge가 만나는 거리를 인코딩하는 방법으로 작동하거든요. 근데 실시간으로 이 데이터를 편집하려면(예: C4 engine이나 3D Coat에서 하는 것처럼) 꽤 힘들겠죠? 저도 edge의 교차점을 제대로 보존하면서 이 데이터를 편집할 실용적인 방법을 찾는데 실패했습니다.. ㅠ_ㅠ
EVO는 폴리곤 생성을 하는 기법이 아닙니다. 이건 CUDA에서 레이트레이싱을 하면서 실시간으로 복셀을 화면에 그려주는 기법입니다. 실시간으로 돌리만큼 꽤 빨라요. (보고 꽤 감동받았습니다. 데모한번 실행해보세요 ^_^) 그리고 복셀 데이터를 볼륨이 아닌 표면(2D 비슷한) 데이터로 저장했다는게 꽤 주목할만 합니다. 하지만 똑같은 문제점이 있지요. 이 데이터를 편집할 수 있는 쉬운 방법이 없어요 -_-
즉, 이 새로운 기법들은 모두 폴리곤 데이터를 복셀데이터로 캡춰한 뒤 아무런 수정없이 다시 보여주는데 유용한 방법이란 겁니다.
물론 전통적인 MC와 CMS를 사용해서 메쉬를 생성해내면 결과가 조금 달라집니다. 하지만 폴리곤 데이터를 완벽하게 재현해내는게 목적이 아니라 복셀 데이터 편집이 목적이라면 그 차이점은 무시해도 될 수준입니다. 편집툴에서 고치는 즉시 결과가 보이기만 하면(WYSIWYG) 어떤 방법을 써도 별 차인 없거든요. 하지만 MC가 CMS보다 최소 30% 이상은 빠릅니다. (둘다 최적화를 하지 않은 C# 프로그램에서 테스트해봤습니다. 물론 당연히 멀티쓰레딩은 했구요)
4. 정점버퍼를 최적화하세요
10 x 10 x 10 복셀에서 메쉬를 생성하면 삼각형이 1~2천개 정도 나오는건 예사입니다. 복셀 밀도가 높고 월드가 넓으면, 1500만개 삼각형도 금방 씁니다. 이 엄청난 정점 데이터를 GPU로 보내려면 느리더라구요. 고사양 그래픽 카드와 저사양 그래픽 카드에서 모두 테스트 해봤는데 둘 다 엄청 느렸습니다... -_-
그러니 간단한 정점버퍼 최적화라도 해주세요. 삼각형들 끼리 정점을 공유하고 인접 표면들끼리의 법선을 평균내는 것 등이요. 이러면 정점버퍼의 크기를 30~50% 정도 줄일 수 있습니다.
5. level-of-details을 쓰세요
정점들을 공유하는것 만으론 충분치 않습니다. 1500만개에서 30~50% 세이브해도 여전히 삼각형 수가 800~1000만 정도거든요. LOD 메쉬도 생성해주세요. 복셀 공간에서 메쉬를 생성하려면(아마 그러셔야 할껄요?) 매 n번째 복셀을 샘플링 하는 방법으로 LOD 메쉬를 만들면 됩니다. (LOD1은 매 2번째, LOD2는 매 4번째 등으로요..)
CMS를 사용하면 LOD를 만드는 게 그리 어렵지 않습니다. 이 알고리듬은 교차점 정보를 가지고 있으므로 LOD사이에서 끊김 현상이 없거든요. 하지만 제가 권해드린 것처럼 MC를 사용하신다면 틈이 벌어집니다. 이 틈을 메꾸는걸 아직 시도해보진 않았습니다만.. 만약 그런다면 TransVoxel 알고리즘을 먼저 시도해볼거 같습니다. Don Williams 아저씨도 이 방법을 써서 성공했다더군요.
높은 LOD 폴리곤으로부터 낮은 LOD들을 생성하는 방법도 있습니다. 이러면 복셀 데이터를 직접 사용하지 않아도 되지요. Voxel Farm이 이 방법을 씁니다. 이 방법의 장점이 하나 있는데요. 높은 LOD 메쉬를 재투영(reproject)해서 낮은 LOD 메쉬에 사용할 노말맵을 만들수 있습니다. 하지만 메쉬 단순화(simplification)는 제 입맛에 안맞더군요. 자세한 이유는 역시 다음 섹션에서... -_-
6. 메쉬 단순화(simplication)이 입맛에 안맞을 수도 있습니다
정점 데이터를 최적화 하는 다른 방법으로 메쉬 단순화 기법이 있습니다. Voxel Farm이 이 방법을 사용하고 결과도 그닥 나쁘지 않습니다. 하지만 전 별로 맘에 안들었습니다. 합쳐질 삼각형과 그러지 않을 삼각형들을 제 맘대로 선택할 수 있는 방법이 매우 제약적이기 때문입니다. 이 삼각형들 선택은 어떤 오차계산(error calculation) 알고리듬을 선택하느냐에 따라 다른데요. 모든 경우에 제대로 작동하는 함수를 도무지 찾을 수가 없더라구요.
이 방법이 다른 분들의 용도에 안맞는다는 말은 아닙니다. 그냥 저에겐 안맞았습니다.
자.. 그럼 이정도면 된듯 하니... 즐겁게 복셀을 주무르세요~ 하악x2~