처음 만들때 복셀 오브젝트의 디테일을 1x1x1부터 8x8x8까지 선택해가며 배치할 수 있게 했었다. 플레이어가 비교적 정밀한 구조물을 제작할 수 있게 하면서도 복셀의 구성 상태가 실제로 정밀하지 않다면 자동으로 1x1x1짜리 오브젝트로 변환하려고 이렇게 만들었다.
메모리를 아끼기 위해, 복셀의 구성상태는 bit-table을 사용한다.
8x8x8짜리 복셀오브젝트라면 복셀 한칸당 1비트를 할당해서 8x8x8 / 8 bytes의 bit-table을 만든다. 복셀의 컬러값은 따로 저장해두는데 이것은 서버로부터 복셀 데이터를 받을때 컬러값은 나중에 받고 일단 구조물부터 먼저 받아서 렌더링하기 위함이다.
나 스스로 복셀을 배치해가면서 실제 나올법한 시나리오에 가까운 구조물을 만들 능력과 시간은 없으므로, 예전 게임에서 사용하던 맵데이터를 복셀 오브젝트로 변환했다(꽤~~ 크고 많은 오브젝트가 나온다). 그리고 이걸 무사히, 그리고 빠르게 렌더링하기 위해서 지난 2주정도를 소모했다.
SW Occlusion Culling, Hi-Z HW Occlusion Culling , D3D Query HW Occlusion Culling, D3D11/12 공통 지원등 이런저런 이슈를 뚫고 이제 깔끔하다~ 라고 생각했다.
그런데 모든 복셀 오브젝트를 8x8x8로 만들어서 렌더링 해보니 1x1x1이었을때보다 한 5-6배는 느리더라.
복셀을 렌더링할때 Constant Buffer로 bit-table(최대 64bytes)만 넘기고 VertexShader->Geometry Shader를 거치며 삼각형 데이터를 생성하게 했다. 이게 8x8x8복셀 오브젝트 렌더링이 느린 이유다.
이렇게 한 이유는 복셀 오브젝트의 개수가 상당히 많아질것이고, 따라서 복셀 오브젝트 개수만큼 VB를 만들면 GPU메모리를 미친듯이 처먹게 될거라 예상했기 때문이다.
하지만 속도차이가 너무 나니 어쩔수 없다. Geometry Shader방식은 버린다. Shadow Map만드는걸 감안하면 중복해서 삼각형을 생성하는것도 꽤 낭비가 심하다.
한참 고민한 끝에 그냥 변경사항이 생길때마다 CPU단에서 삼각형을 만들어 주기로 했다. 하지만 오브젝트 개수가 3차원 상에서 꽉 차게 되면 그 양이 장난 아닌지라 최악의 사태를 대비하여 VB를 오브젝트 개수만큼 만들진 않기로 했다. 일반적으로 실제 렌더링하는 오브젝트 개수는 대략 월드 전체의 1/8 – 1/4 정도가 되므로 VB는 예상 가능한 최대개수의 1/4정도만 만들어두고 이걸 heap으로 쪼개서 Cache처럼 쓸 것이다.
복셀의 기하학적 형태는 bit-table에 기록되어있고 bit-table이 최대 64bytes니까 bit-table을 64bytes key로 사용해서 검색하면 된다. 해당 key에 대한 VB가 만들어져있으면 그대로 재사용. 없으면 새로 만들고 만들어둔 VB가 부족하면 가장 오래된 VB부터 반환. 뭐 이런식으로…
전략구상은 끝.
몇일 실행도 못해보고 코딩만 하겠네.