프로그래밍 언어 입문서가 아닌 프로그래밍 기초 개념 입문서
문과생, 비전공자를 위한 프로그래밍 입문책입니다.
jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다.

Vertex Compression

프로그래밍 2011. 12. 12. 02:00
Posted by cagetu
예전에 개인 블로그에 적은 적이 있기는 한데, 다시 한번 정리해서 올려보겠습니다. 
이전에 Nebula3 라는 공개용 엔진을 참 많이 봤었는데, 그 엔진 기능 중에 Vertex Component Packing 이라는 제목의 관심 있는 포스팅이 하나 있었습니다. 말 그대로 버텍스의 사이즈를 줄여보자는 것입니다. 버텍스 사이즈를 줄임으로써 얻는 이득이 몇 가지가 있는데요.
- 첫째, 게임에서 mesh 리소스의 사이즈를 줄일 수 있습니다. 이게 별거 아닌 것 처럼 느껴지겠지만, 게임을 릴리즈 할 때 정도 되면, 엄청난 양의 리소스 데이터를 줄일 수 있다는 이야기가 됩니다.
- 두번째, 전체적이 로딩 시간을 줄일 수 있습니다.
- 세번재, 전체적인 버텍스 버퍼의 크기를 줄여주기 때문에, 그래픽 카드로 버텍스 데이터를 전송할 때, 버텍스 처리량(vertex though-put)이 좋아집니다.

물론, 추가적인 shader에서 연산이 들어갑니다. 하지만, 얻어지는 이득과는 Trade-Off 관계이기 때문에, 상황에 맞게 선택을 하면 되겠습니다.

Vertex 압축

패킹된 버텍스 구조의 최종 모습은 이렇습니다.

[Nebula3]

각 Comonent이 가지는 특성을 이용해서, 값의 범위에 따라 적절하게 값을 압축하는 형태입니다.


* Position
Position의 경우, 비교적 높은 정밀도와 표현 가능한 값의 범위가 굉장히 광범위 하게 때문에, 사실 압축을 하기란 쉽지가 않습니다. 따라서, 일반적으로 포지션 압축은 사용하지 않습니다.
 
*Texture Coord
텍스쳐 좌표의 경우, [0, 1] 사이의 범위를 가지고, 일반적인 텍스쳐의 경우에는 정밀도가 매우 중요한 편이 아닙니다. 따라서, Texture 좌표의 경우에는 압축을 시도해볼 만 합니다. float을 고정 소수점(Fixed Point)로 변환하여, float2 -> short2로 변환을 합니다. 이렇게 되면, 8Byte의 값을 4Byte로 변환을 할 수 있습니다. 4.12 Fixed Point 변환을 주로 이용하는데, 16비트 중 12비트를 왼쪽으로 이동시키는 것입니다. 혹은 4096으로 나누어 준다고 하면 빠르겠군요. 즉, c++에서 4096으로 나누어 주고, shader에서 4096을 곱해주어서 복원해주는 형태입니다.

- Normal/Tangent/Binormal :
노말은 [-1, 1]의 범위를 가지고 있고, 정밀도 또한 그렇게 중요한 편은 아닙니다. 이는 UBYTE4를 이용하면, 좋은데요. UBYTE4 계열의 특성에 대해서 먼저 알아보자면,

- UBYTE4 : 0 ~ 255 범위의 unsigned char형 4개 (BGRA)
- UBYTE4N : 0 ~ 1 범위의 unsigned char형 4개 (BGRA)
(geforce 7xxx 이상의 그래픽 카드에서부터 지원!!!) 
 

Normal의 경우에는 UBYTE4N을 사용합니다. 이 결과, 12Byte(float*3) -> 4Byte(ubyte4n)으로 줄일 수 있습니다.  http://www.gamedev.net/topic/491408-how-to-design-a-mesh-class-/ 를 참고하시면, 어떻게 압축을 하는지 코드를 보실 수 있습니다.

- Skin Weights
Skin Weight의 경우, [0~1] 사이 범위의 값을 가지기 때문에, 이는 UBYTE4N 형을 사용해서 압축을 하면, 그대로 이용이 가능한 범위입니다. 이를 통해서 float4(16byte)를 UBYTE4N(4byte)로 줄일 수 있군요. 하지만, 이 경우, 정밀도가 영향을 줄 수 있기 때문에, 셰이더에서 다시 한번 정규화를 해주어서, 전체적인 weight를 보정해줍니다.
기본적으로 normal과 동일하게 처리가 되지만, [0, 1]의 범위이기 때문에,  노말과 같이 [-1, 1] -> [0, 1]로 변환해주는 과정 (normal * 0.5f + 0.5f)을 할 필요가 없이 바로 UBYTE4N로 변환을 할 수 있습니다.

return (packedWeights / dot(packedWeights, float4(1, 1, 1, 1)));


- Skin Index
Skin 의 본 인덱스의 경우, [0, n]의 값 범위를 가지게 되는데, bone의 개수가 255를 넘지 않는다며, UBYTE4의 특성을 이용해서, 압축이 가능합니다. 이 결과로 float4(16byte)를 ubyte4(4byte)로 압축이 가능합니다.

이 결과 버텍스 하나가 position(float4), normal(float3), uv(float2), skinweights(float4), skinindices(float4)로 구성되어 있을 때, 압축을 하면, 64Byte -> 28Byte로 버텍스의 사이즈를 줄여줄 수 있습니다. 

결론
 최근 온라인 게임의 리소스 데이터의 용량이 1G가 넘어가는 경우는 이미 일반적입니다. 이러한 상황에서, 리소스 데이터를 다운로딩하는 시간을 줄이는 것 또한 많은 개발사에서 고민을 하고 있습니다. 특히, 해외 서비스를 하는 경우에는 더욱이 이러한 필요성을 더욱 많이 느끼고 있습니다.
이런 고민의 해결책 중 하나가 vertex 압축이 될 수도 있습니다. 약간의 vertex shader 추가적인 연산을 통해서, 데이터 사이즈를 1/3 정도로 줄일 수 있다면, 충분히 시도해볼만한 작업이라고 생각합니다.
 

참고자료
- http://cagetu.egloos.com/4941476
- http://zho.pe.kr/view.html?file_name=doc/vtxprg.txt
http://flohofwoe.blogspot.com/2008/03/vertex-component-packing.html
TAG

댓글을 달아 주세요

  1. Favicon of https://gamedevforever.com 김포프 2011.12.12 05:29 신고  댓글주소  수정/삭제  댓글쓰기

    좋은글 감사합니다. cagetu님 말대로 요즘 vertex 압축 많이 합니다. 특히 메모리가 딸리는 콘솔에선 더더욱 그렇지요. 저흰 PS3에서 메모리 아끼려고 vertex들 다 압축시켜서 메모리에 올려놓은뒤 매 프레임마다 SPU돌려서 uncompress합니다. ㅋ

    위에서 드신 예에서 4바이트 더 줄일 수 있는 방법으로 binormal을 저장 안하는 법도 있습니다. normal과 tangent만 있으면 쉐이더 안에서 외적을 통해 binormal을 쉽게 구할 수 있거든요. 속도도 그리 느리지 않습니다. 어차피 외적이 쉐이더 어셈블리로 하면 MADD(multiply + add) 하나일테니까요. 물론 방향에 따라 -1을 다시 곱해줘야할수도 있지만 +1인지 -1인지는 tangent의 4번째 컴포넌트(w)에 슬쩍 인코딩 해도 되니까요. ^^

    • Favicon of http://cagetu.egloos.com cagetu 2011.12.12 09:43  댓글주소  수정/삭제

      ㅎㅎ.. 온라인에서는 생각보다 버텍스 압축을 많이 사용하지 않는 편인 것 같아요. 하지만, 해외 서비스를 하는 곳들 중에서는 이런 다운로드 용량 때문에 고민이 많은 것 같더라구요. 극단적으로 길드워처럼 스트리밍이 적용되어야 한다면, 더욱 이런 처리가 빛을 낼 수 있을 것 같은데... ㅎ

      물론, 리소스 파이프라인을 구축할 때, 데이터를 압축된 포멧으로 뽑느냐 마느냐에 따라서, 또 다른 고민이 시작되긴 하겠네요. ^^

    • Favicon of https://gamedevforever.com 김포프 2011.12.12 11:49 신고  댓글주소  수정/삭제

      MMO같은 경우에는 메모리에 올릴때 압축을 푸는 경우도 있더라구요. procedural texture generation 하는 Substance도 그런식으로 하더라는~

  2. Favicon of https://gamedevforever.com 귀거리 2011.12.12 14:30 신고  댓글주소  수정/삭제  댓글쓰기

    잘은 모르지만 잘읽었습니다..나중에 서비스할때 도움이 될만한 글인것 같네요 저희 프로그래머들에게 공유하겟습니다 ^^

  3. 감사함. 2012.01.18 11:42  댓글주소  수정/삭제  댓글쓰기

    퍼갈께요.