3D 모델은 왜 이렇게 무거울까?
모델은 몰래 살찌고 있다
GLB 파일을 하나 내보냈습니다. 10MB. 괜찮은 것 같죠. 폰에서 열어보면——하얀 화면, 버벅임, 심하면 그냥 crash.
컴퓨터에서는 문제없는데 폰에서는 폭발합니다. 이건 코드 탓이 아닙니다. 3D 모델에는 직관에 반하는 성질이 있기 때문입니다: 디스크상과 VRAM에서의 크기가 완전히 다릅니다.
JPG 이미지는 디스크에서 200KB 정도일 수 있습니다. 하지만 GPU는 JPG를 이해하지 못합니다. 이해하는 건 raw pixel뿐입니다. 그래서 VRAM에 업로드하기 전에 이미지는 완전히 해제됩니다. 2048x2048 텍스처는 해제 후 약 22MB의 VRAM을 잡아먹습니다. 텍스처 6장(albedo, normal, roughness, metallic, AO, emissive)을 쓰면 머티리얼 하나만 132MB입니다.
폰의 VRAM은 전부 합쳐 2-4GB 정도밖에 안 될 수 있습니다. 그런데 모델 하나의 텍스처가 3-6%를 차지합니다. 씬에 모델이 10개라면?
뜯어보자: 용량은 어디로 가고 있나
전형적인 GLB 모델은 크게 세 부분으로 이루어집니다: 정점 데이터, 텍스처, 그리고 메타데이터와 애니메이션.
실제 PBR 모델을 보겠습니다:
| 구성 요소 | 내용 | 일반적 비율 | 비고 |
|---|---|---|---|
| 텍스처 | albedo, normal, roughness, metallic, AO 등 | 70-85% | 거의 항상 용량의 대부분 |
| 정점 데이터 | position, normal, UV, tangent, color | 10-20% | 모델 복잡도에 따라 |
| 애니메이션 데이터 | 스켈레톤, 스키닝, 키프레임 | 0-15% | 애니메이션이 있을 때만 |
| 기타 | 머티리얼 정의, 씬 구조, 카메라 | < 2% | 무시 가능 |
텍스처가 약 80%를 차지합니다. 최적화해야 할 게 정점이라고 생각하기 쉽지만, 실제로 자리를 차지하는 건 텍스처입니다.
"디스크가 작다"가 "VRAM도 작다"는 아니다
이것이 3D 퍼포먼스를 이해하는 데 가장 중요한 포인트일 겁니다.
PNG와 JPG는 네트워크 전송을 위해 설계되었습니다——디스크에서는 작고 다운로드도 빠릅니다. 하지만 GPU는 이걸 직접 쓸 수 없습니다. raw pixel로 완전히 해제해야 합니다. 계산식:
VRAM 사용량 = 너비 * 높이 * 4바이트(RGBA) * 1.333(mipmap 포함)
4096x4096 RGBA 텍스처:
| 지표 | 값 |
|---|---|
| PNG 파일 크기 | ~8MB |
| JPG 파일 크기 | ~1.5MB |
| VRAM 사용량(mipmap 포함) | ~87MB |
1.5MB짜리 JPG가 VRAM에서는 87MB가 됩니다.
mipmap이란? GPU는 텍스처에 대해 점진적으로 작아지는 일련의 버전을 생성합니다. 원래 크기부터 1x1 픽셀까지, 각 레벨은 이전 레벨의 절반입니다. 이것은 멀리 있는 오브젝트를 더 빠르고 선명하게 렌더링하지만, VRAM을 약 33% 더 사용합니다. 거의 모든 3D 앱이 mipmap을 쓰므로 이 오버헤드는 사실상 표준입니다.
즉, PNG와 JPG는 압축 보관백 같습니다——여행할 때 작게 압축하지만, 목적지에서는 전부 펼쳐야 합니다. 다운로드는 빨라졌지만 VRAM 절약은 없습니다.
VRAM이 부족하면 어떻게 되나
"메모리 부족"이라는 깔끔한 대화상자는 뜨지 않습니다. 현실은 더 심합니다:
- 모바일: 하얀 화면, 또는 OS가 탭을 바로 종료
- VR 헤드셋: 프레임 드랍. VR에서 프레임 드랍은 "약간 버벅임"이 아니라 멀미를 유발합니다
- 데스크톱: 텍스처 깜빡임, 품질 저하, 렌더링 지연
Reddit에서 한 개발자가 WebXR 갤러리를 만들어 Quest에 입체 이미지 60장을 쑤셔넣었습니다. 처음엔 정상이었지만 점점 불안정해지다 crash가 났습니다. 그는 며칠간 코드를 디버깅한 뒤에야, VRAM을 진지하게 생각해 본 적이 없다는 걸 깨달았습니다——그냥 계속 GPU에 JPG를 쑤셔넣고 있었을 뿐입니다.
압축의 두 가지 길
3D 모델 압축은 두 방향으로 나뉩니다:
정점 압축——정점 좌표, 노멀, UV 같은 지오메트리 데이터를 더 작게 저장합니다. 예컨대 32비트 float을 16비트 정수로 바꾸는 것(이를 양자화라고 합니다). 대표 솔루션: Draco, MeshOpt, KHR_mesh_quantization.
텍스처 압축——VRAM 안에서도 텍스처를 압축된 상태로 유지합니다. GPU는 샘플링할 때 개별 픽셀을 즉석에서 디코딩하며, 퍼포먼스 비용은 거의 없습니다. 대표 솔루션: KTX2 + Basis Universal.
| 정점 압축 | 텍스처 압축 | |
|---|---|---|
| 무엇을 줄이나 | 지오메트리 데이터 | 텍스처 |
| 일반적 효과 | 50-90% 축소 | 디스크 50-70% 축소, VRAM 75% 절감 |
| 손실 있나 | 네, 정밀도 저하 | 네, 품질 저하 |
| 적합한 경우 | 정점이 밀집된 모델 | 거의 모든 PBR 모델 |
| 자세히 | 제2편 | 제3, 4편 |
흔한 오해: Draco로 정점을 압축하고 끝. 하지만 텍스처가 모델 용량의 80%를 차지합니다. 정점을 반으로 줄여도 전체는 10%밖에 줄지 않을 수 있습니다. 양쪽을 모두 다뤄야 합니다.
모든 상황에 통하는 단일 방법은 없다
이것이 전체 시리즈의 핵심 주장입니다:
플랫폼, 기기, 용도가 다르면 필요한 압축 전략도 다릅니다.
| 시나리오 | 주요 병목 | 중점 |
|---|---|---|
| 데스크톱 Web 전시 | 다운로드 속도 | 파일 크기 |
| 모바일 브라우저 | VRAM | 텍스처 압축 |
| VR 헤드셋 | VRAM + 프레임레이트 | 텍스처 압축 + 정점 단순화 |
| 위챗 미니 프로그램 | 패키지 크기 + 호환성 | 가벼운 솔루션(MeshOpt) |
| 대형 씬 | VRAM + 드로우 콜 | 전면 압축 + LOD |
앞으로의 각 글은 "X를 쓰면 된다"고만 말하지 않습니다. X가 빛나는 상황, 오히려 독이 되는 상황, 그리고 Y를 선택해야 하는 상황을 설명합니다.
다음 단계
이 글에서는 문제를 정리했습니다. 다음 글은 실전입니다——정점 압축의 세 가지 도구, 양자화, MeshOpt, Draco를 만나보세요.