Unity의 일반적인 본 애니메이션에서는 본 갱신 등 재생을 위한 계산을 매 프레임 CPU가 수행합니다. 따라서 애니메이션하는 오브젝트가 늘어날수록 CPU 부하가 누적되어 프레임 레이트 저하의 원인이 됩니다. 이 장에서는 이러한 런타임 계산 전체를 사전 계산으로 대체하여 부하를 줄이는 기법인 VAT를 소개합니다.
VAT는 Vertex Animation Texture의 약자로, 애니메이션에 의한 버텍스 변형 정보를 미리 텍스처에 베이크해 두고 버텍스 셰이더에서 읽어 재생하는 기법입니다. 텍스처의 픽셀 하나하나가 '특정 버텍스의 특정 프레임에서의 위치'에 대응하며, 재생 시간에 맞춰 읽는 위치를 옮겨 가면 메시가 움직이는 것처럼 보이는 구조입니다(그림 3.1). 또한 위치는 정밀도를 확보하기 위해 0에서 1로 정규화한 값으로 저장되며, 버텍스 셰이더에서 실제 좌표로 복원합니다.
그림 3.1: VAT 텍스처의 구조. 가로축이 버텍스, 세로축이 프레임에 대응한다
VAT를 사용하면 본 갱신 등 런타임 재생 계산 전체를 사전 계산으로 대체할 수 있습니다. 이는 GPU Skinning으로도 얻을 수 없는 효율화입니다.
한편, 다음과 같은 단점이 있습니다.
이러한 특성 때문에 VAT는 대량의 오브젝트에 정해진 애니메이션을 재생할 때 특히 효과적입니다. 예를 들어 건물 파괴 표현, 군중, 배경 장식물처럼 개별 제어가 필요 없는 연출에 적합합니다(그림 3.2).
그림 3.2: VAT에 의한 애니메이션(왼쪽: 강체, 오른쪽: 소프트 바디)
VAT의 성능을 다른 애니메이션 방식과 실기기에서 비교한 결과를 소개합니다.
계측 환경을 표 3.1에 나타냅니다.
표 3.1: 계측 환경
| 항목 | 내용 |
|---|---|
| 실기기 | Pixel 8a(GPU: Mali-G715) |
| 그래픽스 API | Vulkan |
| Unity 버전 | 6000.3.2f1 |
| 계측 API | FrameTimingManager, ProfilerRecorder |
| 모델 | 건물 붕괴 애니메이션(85,209 버텍스, 파편 1,315개) |
| 애니메이션 | 300 프레임 |
| 계측 방법 | 오브젝트 수를 0~16개체로 변화, 각 조건 300 프레임×3회의 중앙값 |
비교한 세 가지 방식을 표 3.2에 나타냅니다.
표 3.2: 비교 조건
| 방식 | 구성 | 활성화한 최적화 |
|---|---|---|
| FBX 방식 | 각 파편을 개별 Mesh Renderer로 배치하고 Animator로 재생 | SRP Batcher |
| Skin 방식 | 1파편 1본으로 하나의 SkinnedMeshRenderer에 통합하고 Animator로 재생 | SRP Batcher |
| VAT 방식 | 모든 파편의 움직임을 텍스처에 베이크하여 하나의 메시로 렌더링(Rigid-Body Dynamics 모드) | GPU Instancing |
FBX 방식은 각 파편을 개별 Mesh Renderer로 두고 Animator로 재생하는 구성입니다(파편은 Transform으로 움직이는 강체이며 스키닝은 사용하지 않습니다). Skin 방식은 파편 하나당 본 하나를 할당하여 전체를 하나의 Skinned Mesh로 합친 구성입니다. 1,315개의 파편이 그대로 1,315개의 본이 되며 Renderer는 하나입니다. 애니메이션 재생은 CPU의 Animator가 담당하고, 버텍스 변형은 GPU Skinning으로 이루어집니다. VAT 방식은 모든 파편의 움직임을 텍스처에 베이크하여 하나의 메시로 렌더링합니다. 세 방식 모두 외형은 동일합니다.
렌더링 효율화 설정은 각 방식에 유리한 것을 활성화한 상태로 비교했습니다. SkinnedMeshRenderer는 GPU Instancing을 지원하지 않으므로 Skin 방식에서 쓸 수 있는 최선은 SRP Batcher입니다. 또한 Skin 방식의 본 변환에도 전용 변환 파이프라인이 필요하며, 이 점은 VAT와 같은 조건입니다.
CPU 처리 시간(메인 스레드)의 계측 결과를 그림 3.3에 나타냅니다. 16개체 표시 시 FBX 방식은 154.3ms까지 늘어나는 반면, Skin 방식은 16.5ms, VAT 방식은 12.6ms로 거의 일정했습니다.
그림 3.3: 오브젝트 수별 CPU 메인 스레드 처리 시간
세부 내역을 표 3.3에 나타냅니다. FBX 방식과 나머지 두 방식의 차이를 만드는 가장 큰 요인은 드로우 콜 전송 처리입니다. FBX 방식에서는 모델 하나당 1,315개의 파편이 렌더링 대상이 되는 반면, 하나의 메시로 합쳐진 두 방식에서는 이 처리가 거의 사라집니다. 파편별 바운딩 박스 계산과 컬링도 마찬가지입니다. 한편 Skin 방식과 VAT 방식의 차이는 Animator 갱신입니다. Skin 방식은 재생을 CPU가 담당하므로 16개체에서 4.5ms가 남지만, VAT 방식은 재생 자체가 GPU로 옮겨 가므로 완전히 사라집니다. 이 차이는 개체 수에 따라 커집니다.
표 3.3: 16개체 표시 시 CPU 처리 시간의 세부 내역(ms)
| 처리 | FBX 방식 | Skin 방식 | VAT 방식 |
|---|---|---|---|
| 메인 스레드 합계 | 154.30 | 16.53 | 12.56 |
| 이 중 드로우 콜 전송(SRPBatcher.Flush) | 76.17 | 0.03 | 0.02 |
| 이 중 Animator 갱신 | 5.30 | 4.54 | 0.02 |
GPU 처리 시간의 계측 결과를 그림 3.4에 나타냅니다. 16개체 시 FBX 방식의 77.1ms에 비해 Skin 방식이 22.2ms로 가장 빨랐고, VAT 방식은 32.5ms였습니다.
그림 3.4: 오브젝트 수별 GPU 처리 시간
FBX 방식과 나머지 두 방식의 차이를 만드는 주된 요인은 드로우 명령의 분할 수입니다. FBX 방식은 파편이 각 렌더링 패스에서 개별적으로 드로우 명령을 발행하므로 프레임당 약 21만 회에 달한 반면, VAT 방식은 인스턴스 렌더링으로 합쳐져 99회였습니다. Skin 방식도 개체당 Renderer가 하나이므로 같은 수준에 머뭅니다. 드로우 명령에는 1회마다 고정 비용이 들기 때문에 분할 수의 차이가 그대로 처리 시간의 차이로 나타납니다.
Skin 방식과 VAT 방식의 차이는 변형 계산 횟수에서 비롯됩니다. GPU Skinning은 변형을 프레임당 한 번만 계산하고, 그 결과를 섀도와 깊이 등 모든 렌더링 패스가 재사용합니다. 반면 VAT는 패스마다 버텍스 셰이더에서 텍스처로부터 변형을 다시 계산합니다. 이번 환경은 섀도 캐스케이드가 4장인, 패스 수가 많은 씬 구성이므로 그만큼 Skin 방식과의 차이가 벌어졌습니다(섀도 맵 렌더링은 FBX 방식 44.3ms, Skin 방식 7.4ms, VAT 방식 16.0ms). 버텍스 계산을 수행하는 패스 수가 적은 구성에서는 이 차이가 줄어듭니다.
GPU 메모리의 계측 결과를 그림 3.5에 나타냅니다. 값은 OS가 집계하는 그래픽스 드라이버의 실측값(GL mtrack)입니다. 0개체에서 16개체로의 증가분은 FBX 방식이 +411.8MB(1개체당 약 26MB), Skin 방식이 +38.2MB(1개체당 약 2.4MB), VAT 방식은 거의 ±0이었습니다.
그림 3.5: 오브젝트 수별 GPU 메모리 확보량
이 차이는 1개체가 늘어날 때 무엇이 늘어나는가 하는 구조의 차이에서 비롯됩니다. FBX 방식은 행렬 등 렌더링용 데이터가 파편 수만큼 GPU 메모리에 확보됩니다. Skin 방식에서 늘어나는 것은 스키닝의 변형 결과를 기록하는 버텍스 버퍼가 개체당 하나뿐입니다. VAT 방식은 변형을 그 자리에서 계산할 뿐 새로운 버퍼를 갖지 않으므로 늘어나지 않습니다. 또한 VAT의 텍스처는 비압축으로 약 6.6MB이지만, 증가분의 차이에 비하면 충분히 작은 값입니다.
16개체 표시 시의 실측값을 표 3.4에 정리합니다.
표 3.4: 16개체 표시 시 실측값 요약
| 지표 | FBX 방식 | Skin 방식 | VAT 방식 |
|---|---|---|---|
| CPU 메인 스레드(ms) | 154.3 | 16.5 | 12.6 |
| GPU 프레임(ms) | 77.1 | 22.2 | 32.5 |
| 드로우 명령 수(회/프레임) | 약 210,000 | VAT 방식과 같은 수준 | 99 |
| GPU 메모리 증가분(0→16개체, MB) | +411.8 | +38.2 | 거의 ±0 |
FBX 방식에 비해 Skin 방식과 VAT 방식 모두 전 지표에서 크게 우수했습니다. 그 요인은 '하나의 메시로 다룰 수 있다는 점'으로 집약됩니다.
Skin 방식과 VAT 방식의 비교는 일장일단이 있어, GPU 처리 시간은 Skin 방식이, CPU 메인 스레드와 메모리는 VAT 방식이 유리합니다. VAT 방식의 GPU 처리 시간은 버텍스 변형 처리가 많이 필요한 패스 구성인지에 크게 좌우됩니다. 따라서 버텍스 계산을 수행하는 패스 수가 적은 구성이나 CPU 부하 절감이 목적인 경우에는 VAT가 첫 번째 후보가 됩니다.
다만 이번 비교는 강체 파괴라는, 본으로 표현하기 쉬운 소재였습니다. 천이나 인체처럼 본 수가 많아지거나 근사 처리가 되어 버리는 모델, 그리고 오브젝트 수가 많은 경우에는 CPU 부하가 두드러지므로 VAT가 더 우세해질 것으로 생각됩니다.
VAT 에셋을 제작할 때는 Houdini에 포함된 Labs Vertex Animation Textures ROP(이하 VAT ROP)를 사용하는 방법이 간편합니다*1. Houdini는 SideFX사의 DCC 툴로, 프로시저럴 생성에 강점이 있습니다. VAT ROP에는 Unity용 프리셋과 대응 셰이더가 준비되어 있으며, Houdini 내 시뮬레이션 결과뿐 아니라 다른 DCC 툴에서 만든 FBX 애니메이션도 입력으로 사용할 수 있습니다.
VAT ROP에는 표 3.5의 네 가지 모드가 있습니다.
표 3.5: VAT ROP의 모드
| 모드 | 용도 |
|---|---|
| Soft-Body Deformation | 기본적인 버텍스 변형. 토폴로지가 변하지 않는 것이 조건 |
| Rigid-Body Dynamics | 강체 파괴에 최적화. 파편 단위로 움직임을 기록하므로 텍스처 크기를 작게 억제할 수 있음 |
| Dynamic Remeshing | 액체나 찢어지는 천 등 토폴로지가 변하는 대상에 대응 |
| Particle Sprites | 파티클 시뮬레이션용 |
절차는 Input Geometry에 VAT로 만들 애니메이션의 노드를, Mode에 사용할 모드를, Target Engine에 Unity를 지정하고 Render All 버튼을 누르기만 하면 됩니다. 표 3.6의 에셋이 일괄 출력됩니다.
표 3.6: VAT 재생에 필요한 에셋
| 에셋 | 역할 |
|---|---|
| 포지션용 텍스처 | 각 버텍스의 각 프레임에서의 위치(0~1로 정규화) |
| 회전용 텍스처 | 변형 후 면의 방향. 노멀과 탄젠트를 재구성하여 음영을 유지 |
| 버텍스 컬러용 텍스처 | Houdini 측 어트리뷰트의 베이크 대상. 보간 품질 향상 등에 쓸 수 있는 자유 슬롯 |
| FBX | 텍스처의 참조 위치를 나타내는 식별 번호가 UV에 포함된 메시 |
| 머티리얼 | 프레임 수, FPS, 바운딩 박스 등의 보조 데이터가 설정되어 있음 |
| 셰이더 | 각 모드에 대응하는 재생 계산 본체(별도 설치) |
셰이더는 출력 파일에 포함되지 않습니다. 계산 처리는 애니메이션과 무관하게 고정이기 때문입니다. Unity의 Package Manager에서 SideFX Vertex Animation Textures 패키지를 별도로 설치합니다(저장 위치는 VAT ROP의 Real-Time Shaders 탭에서 확인할 수 있습니다). 패키지에는 4개 모드에 대응하는 Shader Graph 외에 문서와 임포트 설정용 Preset이 포함되어 있습니다.
VAT는 정밀도가 부족하면 애니메이션이 깨지므로 텍스처에 적합한 포맷을 지정해야 합니다. 마찬가지로 FBX 측에도 권장되는 임포트 설정이 있습니다. 패키지에 포함된 'VAT Import Settings Guide'에 따라 텍스처 압축 비활성화를 비롯한 전용 임포트 설정을 적용하시기 바랍니다.
또한 공식 Shader Graph는 어디까지나 템플릿이라는 위치이며, 실사용에서는 커스터마이즈가 필요합니다. 템플릿을 직접 이용하지 않고 프로젝트용으로 복사한 뒤 사용하게 됩니다. 다만 복사본 Shader Graph는 패키지 측 Sub Shader Graph를 참조한 채로 남으므로, 복사한 쪽으로 참조를 교체해 두어야 한다는 점에 주의하시기 바랍니다.
그리고 출력 파일의 임포트 설정이나 머티리얼에 대한 텍스처·셰이더 할당 같은 참조 설정은 수작업으로 해야 하며, 설정 누락으로 인한 문제가 생기기 쉬운 부분입니다. 대량 제작하는 프로젝트에서는 Scripted Importer 등으로 임포트 설정과 참조 해결을 자동화할 여지가 있습니다. 이 부분의 개선에 대해서는 CEDiL에 업로드된 자료를 확인하시기 바랍니다*2.
VAT는 애니메이션을 텍스처에 베이크하여 GPU에서 재생하는 기법입니다. 드로우 콜을 크게 줄일 수 있는 것이 특징이며, 파편마다 Renderer를 두는 구성에 비해서는 Skin 방식과 함께 대폭 효율적이었습니다. 두 방식은 일장일단이 있어, GPU 처리 시간은 Skin 방식이, CPU 처리 시간과 메모리는 VAT 방식이 유리합니다. 버텍스 계산을 수행하는 패스 수가 적은 구성이나 CPU 부하 절감이 목적인 경우에는 VAT가 첫 번째 후보가 됩니다. 전용 에셋을 준비해야 하고 움직임이 고정된다는 제약이 있지만, 대량의 오브젝트에 정해진 애니메이션을 재생하는 상황에서는 강력한 선택지가 됩니다.
[*1] SideFX Labs 패키지에 포함된 툴입니다. 이 장의 검증에는 버전 3.0을 사용했습니다.