웹용 GLB 파일 최적화 방법: Draco, Meshopt, KTX2 (2026)
최종 업데이트: 2026년 9월.

웹용 GLB를 최적화할 때는 다음 순서로 작업하세요. 먼저 텍스처를 축소하고(1024 또는 2048로 제한한 뒤 다운로드 용량을 줄이려면 WebP로, GPU 메모리를 줄이려면 KTX2로 다시 인코딩), 버텍스 데이터를 양자화한 다음, Meshopt로 지오메트리를 압축합니다. 디코딩 시간보다 마지막 수백 킬로바이트를 줄이는 것이 더 중요하다면 Draco를 사용하세요. 그래도 삼각형 수가 터무니없이 많다면 메시를 단순화하고, 마지막으로 남은 요소를 정리하고 중복을 제거한 뒤 결합합니다. gltf-transform optimize in.glb out.glb --texture-compress webp 명령어 하나로 대부분을 처리할 수 있습니다. 텍스처는 보통 파일 용량의 80% 이상을 차지하고 비디오 메모리도 대부분 사용하므로 작업 순서가 중요합니다.
빠른 답변
- 텍스처 비중이 큰 모델(대부분의 모델): 1024 또는 2048로 크기를 조정한 다음
gltf-transform webp를 실행하세요. 휴대폰에서 끊기거나 충돌한다면 브라우저의 KTX2 압축기 또는gltf-transform etc1s/uastc를 사용해 KTX2로 변환하세요. - 지오메트리 비중이 큰 모델(스캔, CAD, AI 생성 모델):
gltf-transform simplify를 실행한 다음meshopt를 적용하세요. Draco는 파일을 조금 더 작게 압축하지만 디코딩이 느리고 디코더 크기가 10배 더 큽니다. - 애니메이션 캐릭터: Draco가 아닌 Meshopt를 사용하세요. Draco는 애니메이션 트랙과 모프 타깃을 압축하지 않습니다.
- 직접 제어할 수 없는 엔진에서도 파일이 열려야 하는 경우:
gltf-transform quantize를 사용하세요. 디코더는 필요하지 않으며, 여기서 다루는 모든 로더가 지원하는KHR_mesh_quantization만 사용합니다. - 터미널을 사용할 수 없는 경우: GLB 최적화 도구는 브라우저에서 정리, 용접, 결합, 단순화, WebP 텍스처 크기 조정, Meshopt를 실행하고 단계별 용량을 표시합니다.
빠른 참조
| 양자화만 적용 | Meshopt | Draco | |
|---|---|---|---|
| 확장 | KHR_mesh_quantization | EXT_meshopt_compression (+ 양자화) | KHR_draco_mesh_compression |
| 압축 대상 | 버텍스 속성(비트 수 감소) | 버텍스, 인덱스, 모프 타깃, 애니메이션 | 삼각형 메시 지오메트리만 |
| 28MB 테스트 모델의 용량 | 22.8MB(gzip 적용 시 8.1MB) | 5.1MB(gzip 적용 시 3.3MB) | 2.6MB(gzip 적용 시 2.5MB) |
| 디코더 | 없음 | 인라인 WASM이 포함된 32KB JS 모듈 | 192~286KB WASM과 58KB 래퍼, 719KB JS 폴백 |
| 디코딩 속도 | 즉시 처리, GPU가 직접 읽음 | 사양 기준 WASM SIMD 사용 시 약 1GB/s | glTF-Transform 문서 기준 Meshopt보다 상당히 느림 |
| 서버에서 gzip/brotli 필요 여부 | 큰 도움이 됨 | 필요, 이를 전제로 설계됨 | 효과가 거의 없음 |
| 로더 | three.js, Babylon.js, PlayCanvas, glTFast | three.js r122+, Babylon.js 5.0+, glTFast(추가 패키지), PlayCanvas는 미지원 | three.js, Babylon.js, PlayCanvas, glTFast(추가 패키지) |
동일한 수치를 막대그래프로 나타내고, 비교 테스트에서 얻은 gltfpack 및 단순화 결과도 함께 표시했습니다.
GLB에서 용량을 차지하는 요소
무엇보다 먼저 gltf-transform inspect model.glb를 실행하세요. 이 명령어는 버텍스 수와 속성 유형이 포함된 모든 메시, 인코딩된 용량과 gpuSize가 포함된 모든 텍스처, 키프레임 수가 포함된 모든 애니메이션을 나열합니다. 이 가이드의 수치는 도구 문서와 확장 사양, 그리고 이번 주에 실제 파일 두 개를 대상으로 gltf-transform 4.5.0과 gltfpack 1.2를 사용해 진행한 비교 테스트에서 가져왔습니다. 이를 통해 흔히 접하게 될 두 가지 유형을 확인할 수 있습니다.
2.2MB 크기의 Sketchfab 소품(로우 폴리 컵)은 삼각형 680개와 39KB의 지오메트리로 구성되어 있었습니다. 나머지 2.18MB는 1024×1024 PNG 세 장이었으므로 텍스처가 파일의 98%를 차지했고, inspect는 밉맵 적용 후 각 텍스처가 5.59MB의 VRAM을 사용할 것으로 추정했습니다. 수작업으로 만든 에셋에서 흔히 볼 수 있는 경우입니다.
28.7MB 크기의 TRELLIS.2 출력은 정반대였습니다. 삼각형 978,226개와 27.5MB의 float32 지오메트리로 구성되었고 텍스처는 1.1MB에 불과했습니다. 하지만 이 두 텍스처의 해상도는 4096×4096이었으며, inspect에 따르면 각각 89.5MB의 VRAM을 사용합니다. 3D 모델 생성기와 비슷한 도구로 만든 모델은 대개 이처럼 밀도가 높고 텍스처가 과도하게 큽니다. 따라서 텍스처 최적화뿐 아니라 지오메트리 최적화 단계도 필요합니다.
인코딩된 텍스처 용량과 GPU 용량은 서로 무관하다는 점에 유의하세요. 동일한 2048×2048 이미지라면 4MB PNG와 200KB WebP 모두 비디오 메모리에서는 원시 픽셀과 밉맵을 포함해 약 22MB가 됩니다. 이 수치를 바꿀 수 있는 것은 KTX2뿐입니다.
아래 여섯 단계는 각 단계가 다음 단계에서 처리해야 할 데이터를 줄이도록 이 순서대로 실행합니다.
1단계: 텍스처
서로 다른 두 가지 문제에는 서로 다른 해결책이 필요합니다.
다운로드 용량은 크기 조정과 재인코딩으로 줄입니다. 대부분의 프롭에는 1024×1024보다 큰 텍스처가 필요하지 않으며, 주인공 캐릭터도 2048보다 큰 텍스처가 필요한 경우는 드뭅니다. gltf-transform resize --width 1024 --height 1024는 업스케일링 없이 최대 크기를 제한하고, gltf-transform webp는 sharp로 다시 인코딩합니다. 컵 모델에서는 WebP만 적용해도 파일이 2.23 MB에서 246 KB로 줄었습니다. 먼저 512로 크기를 조정하자 해당 크기의 프롭에서 눈에 띄는 변화 없이 96 KB까지 줄었습니다. WebP에는 EXT_texture_webp가 필요합니다. 웹 엔진은 이를 지원하지만 Unity의 glTFast는 지원하지 않습니다. 기능 표에도 "지원될 예정이 없다"고 명시되어 있습니다.
GPU 메모리와 업로드 시간은 Basis Universal 초압축을 사용하는 KTX2로만 줄일 수 있습니다. 텍스처가 GPU 블록 포맷을 유지한 채 VRAM에 들어가므로 원시 RGBA보다 메모리를 4~8배 적게 사용합니다. 설정이 중요하므로 아래에서 별도 섹션으로 다룹니다.
비교 테스트에서 확인된 주의점이 하나 있습니다. gltf-transform optimize의 기본값은 --texture-compress auto이며, 텍스처를 원래 포맷으로 다시 인코딩합니다. 컵 모델에서는 이 때문에 PNG가 더 커져 파일 용량이 2.2 MB에서 2.8 MB로 증가했습니다. webp 또는 ktx2를 명시적으로 지정하세요.
2단계: 양자화
양자화는 각 버텍스 속성을 더 적은 비트로 저장합니다. 위치 값은 32비트 부동소수점 3개에서 16비트 정수 3개로 바뀌며, 스케일과 오프셋은 노드 트랜스폼에 통합됩니다. 스킨드 메시에서는 inverseBindMatrices에 통합됩니다. KHR_mesh_quantization 사양에 따르면 일반적인 버텍스의 크기는 약 48바이트에서 20바이트로 줄어듭니다. 별도 디코더가 필요 없는 공식 Khronos 확장입니다. GPU가 정수 속성을 직접 읽으므로 전송 용량뿐 아니라 VRAM 사용량도 줄어듭니다.
glTF-Transform의 기본값은 위치 14비트, 노멀과 탄젠트 10비트, UV 12비트, 색상과 웨이트 8비트입니다. gltfpack의 기본값은 각각 14, 8, 12, 8비트입니다. 거대한 단일 메시가 아니라면 둘 다 시각적인 차이가 없습니다. 거대한 메시에서는 전체 범위에 걸친 14비트 정밀도로 인해 표면이 각져 보일 수 있습니다. 양자화만으로 얻는 효과는 크지 않습니다. 28 MB 테스트 모델은 원시 용량 22.8 MB, gzip 압축 시 8.1 MB로 줄었습니다. 양자화의 진짜 역할은 Meshopt 처리의 전반부가 되는 것이며, 대상 로더의 지원 여부가 불확실할 때 안전한 출력 형식을 제공하는 것입니다. Draco는 동일한 기본값으로 내부에서 양자화하므로 draco 전에 quantize를 실행하지 마세요.
3단계: Meshopt 또는 Draco
둘 다 GPU 업로드 전에 일반 버퍼로 디코딩되는 손실형 지오메트리 코덱이므로 모델의 렌더링 속도를 높이지는 않습니다. 줄어드는 것은 다운로드 용량입니다. 차이는 압축 대상, 디코딩 속도, 함께 배포해야 하는 디코더 크기에 있습니다.
Meshopt(EXT_meshopt_compression)는 bufferView 수준에서 작동하므로 버텍스 속성, 인덱스, 모프 타깃 델타, 애니메이션 키프레임이 모두 압축됩니다. 양자화 위에 적용되고 gzip 또는 brotli 아래에서 작동하도록 설계되었습니다. 코덱이 바이트를 규칙적인 형태로 만들면 CDN의 범용 압축기가 나머지를 처리합니다. 사양에 따르면 WebAssembly SIMD 사용 시 디코딩 속도는 약 1 GB/s이며, three.js 디코더는 32 KB짜리 단일 모듈입니다. 테스트 모델에서는 기본 --level high 설정으로 원시 용량 5.1 MB, gzip 압축 시 3.3 MB였습니다.
Draco(KHR_draco_mesh_compression)는 삼각형 메시 프리미티브만 압축합니다. 애니메이션, 모프 타깃, 점, 선은 압축되지 않은 채 유지됩니다. 압축률은 더 높아서 같은 모델이 2.6 MB로 줄었으며, 출력이 이미 조밀해 gzip을 적용해도 거의 줄어들지 않습니다. 그 대가는 디코딩 시간과 디코더 용량입니다. glTF-Transform 문서에는 Meshopt의 디코딩 속도가 훨씬 빠르다고 명시되어 있습니다. three.js에 포함된 WASM 디코더는 286 KB이며, glTF 브랜치 빌드는 192 KB입니다. 여기에 58 KB 래퍼와 719 KB JavaScript 폴백도 있습니다. Draco는 버텍스 순서를 바꾸며 버텍스 개수도 변경할 수 있습니다.
따라서 애니메이션이 있는 에셋, 모프 타깃이 있는 에셋, 모바일 로딩 시간이 중요한 에셋, brotli를 켜서 제공하는 에셋에는 Meshopt를 사용하세요. 에셋이 정적 메시이고 지오메트리가 대부분의 용량을 차지하며, 전송량을 20~30% 더 줄이는 대신 첫 프레임이 느려져도 괜찮다면 Draco를 사용하세요. 확실하지 않다면 Meshopt를 선택하세요. gltfpack의 -cc(더 강한 Meshopt 모드)는 같은 파일에서 원시 용량 4.4 MB, gzip 압축 시 3.1 MB를 기록했습니다.
4단계: 단순화
압축 후에도 모델이 크다면 삼각형이 너무 많은 것이며, 어떤 코덱으로도 이 문제를 해결할 수 없습니다. 두 도구 모두 meshoptimizer 단순화 도구를 사용합니다. 목표 비율과 오차 한계를 지정하면 둘 중 하나에 먼저 도달했을 때 처리를 중단합니다.
gltf-transform simplify --ratio 0.25 --error 0.01은 메시 반경 대비 편차를 1% 이내로 유지하면서 버텍스를 25%로 줄이는 것을 목표로 합니다. 삼각형 978,000개 모델에 적용하자 삼각형이 244,556개로 줄었고 압축 전 용량은 8.1 MB가 되었으며, 게임에서 보는 거리에서는 동일해 보였습니다. optimize의 기본값은 예상보다 훨씬 공격적입니다. --simplify-ratio 0과 --simplify-error 0.0001은 "오차 0.01% 이내에서 최대한 많이 제거"하라는 의미입니다. 같은 과도하게 테셀레이션된 모델이 삼각형 6,582개까지 줄었습니다. 생성기가 평평한 표면에 거의 100만 개의 삼각형을 사용했기 때문입니다. 단순화 전에 버텍스를 웰드하세요. optimize는 이 작업을 자동으로 수행합니다. 분리된 버텍스가 있으면 심에서 단순화가 중단되기 때문입니다.
gltfpack의 -si 0.25도 같은 방식입니다. -se 0.01은 기본 오차 한계이며, -sa는 품질과 관계없이 목표 비율에 도달하게 하고, -slb는 경계 버텍스를 고정해 모듈형 메시 사이에 틈이 생기지 않도록 합니다. 하드 서피스 프롭은 대개 50% 감소를 쉽게 견디며, 스캔 또는 AI 생성 메시는 보통 90%를 제거해도 괜찮습니다. 리깅된 캐릭터는 버텍스를 축소할 때 스킨 웨이트도 함께 축소되므로 관절 주변을 주의해야 합니다.
5단계: 정리, 중복 제거, 병합, 인스턴싱
이 단계들은 품질 손실 없이 얻을 수 있는 이점이며 optimize는 모두 실행합니다. prune은 어디에서도 참조하지 않는 머티리얼, 텍스처, 액세서, 노드를 제거하고 단색 텍스처를 머티리얼 팩터로 변환합니다. dedup은 익스포터가 중복으로 작성한 동일한 액세서와 텍스처를 병합합니다. flatten은 계층 구조를 평탄화하고, join은 같은 머티리얼을 공유하는 메시를 병합합니다. 드로 콜 200개를 몇 개로 줄이는 작업이 바로 이것입니다. instance는 5개 이상 반복되는 메시를 EXT_mesh_gpu_instancing으로 변환하고, palette는 색상만 다른 머티리얼을 병합합니다.
리깅된 캐릭터나 게임에서 파트별로 움직이는 오브젝트에는 join 또는 flatten을 사용하지 마세요. 각 파트가 하나의 메시로 합쳐지기 때문입니다. gltfpack에서는 -kn으로 이름이 지정된 노드를 유지하고 -km으로 이름이 지정된 머티리얼을 유지할 수 있습니다.
6단계: 애니메이션
익스포터는 흔히 모든 프레임에 키프레임을 베이크합니다. gltf-transform resample은 인접 키프레임 사이의 직선상에 있는 키프레임을 제거하며, 기본 허용 오차는 1e-4입니다. 실질적으로 무손실입니다. gltfpack의 -af 30은 모든 트랙을 30 Hz로 리샘플링하고, 이동을 16비트, 회전을 12비트, 스케일을 16비트로 양자화한 뒤(-at, -ar, -as) Meshopt로 압축합니다. 클립이 몇 개뿐인 일반적인 캐릭터에서는 효과가 작지만, 모션 라이브러리에서는 대부분의 용량을 줄일 수도 있습니다.
명령줄
glTF-Transform CLI는 npm install --global @gltf-transform/cli로 설치하거나 npx @gltf-transform/cli로 실행할 수 있습니다. 한 번에 처리하려면 다음과 같이 실행합니다.
gltf-transform optimize in.glb out.glb --texture-compress webp --texture-size 1024이 명령은 순서대로 dedup, instance, palette, flatten, join, weld, simplify(비율 0, 오차 0.0001), resample, prune, sparse, 최대 크기 1024의 텍스처 압축, level high의 Meshopt를 실행합니다. Draco를 사용하려면 --compress draco, 양자화만 적용하려면 --compress quantize, 리깅되거나 관절 구조가 있는 모델에는 --no-join --no-flatten, 실루엣이 용량보다 중요하다면 --simplify false, KTX-Software가 설치되어 있다면 --texture-compress ktx2를 추가하세요.
세부적으로 제어하려면 각 단계를 따로 실행하세요.
gltf-transform inspect in.glb
gltf-transform resize in.glb a.glb --width 1024 --height 1024
gltf-transform webp a.glb b.glb --quality 80
gltf-transform weld b.glb c.glb
gltf-transform simplify c.glb d.glb --ratio 0.5 --error 0.001
gltf-transform meshopt d.glb out.glb --level high마지막 줄을 gltf-transform draco d.glb out.glb로 바꿀 수도 있습니다. --encode-speed와 --decode-speed는 0부터 10까지이며 기본값은 5이고, 값이 낮을수록 용량이 작아집니다. 또는 gltf-transform quantize d.glb out.glb를 사용하세요.
gltfpack은 npm install -g gltfpack으로 설치하거나 meshoptimizer 릴리스에서 네이티브 바이너리를 받을 수 있습니다. README에서는 대용량 파일에 네이티브 바이너리를 권장합니다. 기본 설정만으로도 양자화, GPU 캐시에 맞춘 버텍스 순서 최적화, 메시 병합을 수행합니다.
gltfpack -i in.glb -o out.glb -cc -si 0.5 -tw -tl 1024 -kn-cc는 고압축 Meshopt 모드입니다. -c는 고속 모드이고, -cf는 디코더가 없는 로더를 위해 압축되지 않은 폴백을 추가합니다. -si 0.5는 -se 0.01 범위 내에서 삼각형을 절반으로 줄입니다. -tw는 텍스처를 WebP로 변환하고 -tl 1024는 텍스처 크기를 제한합니다. -kn은 이름이 지정된 노드를 유지합니다. KTX2를 사용하려면 -tw를 -tc(ETC1S) 또는 -tc -tu(UASTC)로 바꾸세요. Basis Universal이 링크된 gltfpack 빌드가 필요합니다.
두 CLI를 모두 사용할 수 없다면 브라우저 도구에서 같은 처리 과정을 실행할 수 있습니다.

KTX2: ETC1S 또는 UASTC
KTX2는 Khronos의 GPU 텍스처 컨테이너입니다. Basis Universal 초압축을 사용하면 텍스처가 로드될 때 기기에서 지원하는 블록 포맷으로 트랜스코딩되며, 데스크톱에서는 BC, 모바일에서는 ASTC 또는 ETC2가 사용됩니다. 이후 메모리에서도 압축 상태를 유지합니다. glTF 확장은 KHR_texture_basisu입니다. Basis에는 두 가지 모드가 있습니다. ETC1S는 용량이 작은 모드입니다. Basis README에 따르면 디스크에서는 픽셀당 약 0.3~3비트를 사용하며, JPEG와 비슷한 품질 설정값(1~255, 기본값 128)을 제공합니다. 메모리에서는 BC1이나 ETC1 같은 형식으로 픽셀당 4비트를 차지합니다. 소품의 베이스 컬러에 사용하세요. UASTC는 품질 중심 모드입니다. 메모리에서 픽셀당 8비트를 사용하고, ASTC 4×4의 19개 모드 하위 집합이며, 품질 단계는 0~4입니다(기본값 2, glTF-Transform 도움말 기준 47.47dB). UASTC 파일은 디스크에서 크기 때문에 Zstandard와 함께 사용하세요. glTF-Transform의 uastc는 기본적으로 --zstd 18을 사용하며, ktx create --zstd는 1~22 값을 받습니다.
밉맵이 있는 2048×2048 텍스처를 계산하면 RGBA8은 약 22MB, UASTC는 약 5.6MB, 4bpp 형식으로 트랜스코딩된 ETC1S는 약 2.8MB입니다.
주의해야 할 규칙은 세 가지입니다. 노멀 맵과 데이터 맵에는 UASTC와 리니어 설정이 적합합니다. glTF-Transform은 RGB 노멀 맵과 오클루전/러프니스/메탈니스 맵이 ETC1S에서 좋지 않게 보일 수 있다고 경고하며, 사양에서는 컬러 텍스처를 sRGB로, 비색상 데이터를 리니어로 지정하도록 요구합니다. glTF-Transform은 슬롯별로 이 설정을 자동 적용합니다. KTX2 압축기에서는 sRGB 토글에 해당하며, 컬러에는 켜고 노멀 및 데이터 맵에는 끕니다. 크기는 4의 배수여야 하며, 2의 거듭제곱을 권장합니다. 밉맵을 생성하세요. 사양에 따르면 밉맵 축소 필터링에 사용되는 KTX2에는 전체 밉맵 피라미드가 포함되어야 합니다. 그렇지 않으면 엔진이 런타임에 압축을 풀고 밉맵을 생성해야 합니다. glTF-Transform과 브라우저 도구에서는 밉맵이 기본적으로 활성화되며, ktx create에서는 --generate-mipmap을 사용합니다.
glTF-Transform 명령에는 KTX-Software의 ktx 바이너리 4.4.0 이상이 필요합니다.
gltf-transform uastc in.glb a.glb --level 2 --zstd 18 --slots "{normalTexture,occlusionTexture,metallicRoughnessTexture}"
gltf-transform etc1s a.glb out.glb --quality 128먼저 데이터 슬롯에 UASTC를 적용하고, 나머지에는 ETC1S를 적용합니다. 베이스 컬러와 이미시브에는 ETC1S, 노멀과 ORM에는 UASTC를 사용하는 것이 일반적인 조합입니다.
결과물 로드하기
양자화를 제외한 모든 코덱에는 클라이언트 측 디코더가 필요합니다.
three.js. GLTFLoader는 별도 설정 없이 KHR_mesh_quantization과 EXT_texture_webp를 읽습니다. 나머지는 디코더를 연결해야 합니다. 디코더는 three 패키지의 examples/jsm/libs/ 아래에 draco/, basis/, meshopt_decoder.module.js로 포함되어 있습니다. draco/와 basis/를 공개 경로에 복사한 다음 다음과 같이 설정합니다.
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js'
import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js'
const draco = new DRACOLoader().setDecoderPath('/libs/draco/')
const ktx2 = new KTX2Loader().setTranscoderPath('/libs/basis/').detectSupport(renderer)
const loader = new GLTFLoader()
.setDRACOLoader(draco)
.setKTX2Loader(ktx2)
.setMeshoptDecoder(MeshoptDecoder)DRACOLoader는 브라우저가 지원하면 WASM 디코더를 선택하고, 지원하지 않으면 JS로 폴백합니다. detectSupport(renderer)를 사용하면 KTX2Loader가 기기의 GPU에 맞는 트랜스코딩 대상을 선택할 수 있습니다.
Babylon.js. glTF 로더는 https://cdn.babylonjs.com에서 디코더를 다운로드하고 웹 워커에서 실행해 Draco, Meshopt(5.0부터 별도 설정 불필요), KTX2를 처리합니다. 직접 호스팅하려면 Tools.CDNBaseUrl을 설정하거나 개별 설정을 지정하세요. Draco는 DracoDecoder.DefaultConfiguration(wasmUrl, wasmBinaryUrl, fallbackUrl), Meshopt는 MeshoptCompression.Configuration.decoder.url, KTX2 트랜스코더 세트는 KhronosTextureContainer2.URLConfig를 사용합니다. npm에서는 @babylonjs/ktx2decoder에 트랜스코더가 번들로 포함됩니다.
PlayCanvas. Draco는 dracoInitialize({ jsUrl, wasmUrl, numWorkers, lazyInit })로 설정하며, Editor에서 임포트할 때 Draco 압축을 적용할 수도 있습니다. KTX2는 basisInitialize({ glueUrl, wasmUrl, fallbackUrl })를 통해 처리합니다. 엔진 2.x 기준으로 EXT_meshopt_compression은 GLB 파서에 포함되어 있지 않으며, 2020년에 등록된 기능 요청도 여전히 열려 있습니다. 따라서 PlayCanvas에서는 Draco 또는 양자화만 적용한 결과물을 선택하세요.
Unity. 공식 임포터는 glTFast(com.unity.cloud.gltfast)입니다. KHR_mesh_quantization은 별도 설정 없이 작동하고, Draco에는 com.unity.cloud.draco, KTX2에는 com.unity.cloud.ktx, Meshopt에는 com.unity.meshopt.decompress가 필요합니다. WebP는 설계상 지원되지 않으므로 Unity를 대상으로 한다면 KTX2를 사용하세요.
모바일 웹 게임 권장 목표
이에 대한 공식 사양은 없지만, 스마트폰에서 원활하게 작동하는 데 도움이 되는 기준은 있습니다. 첫 장면 전체의 전송 용량을 약 10MB 미만으로 유지하고 나머지는 스트리밍하세요. 에셋 스트리밍 로딩 튜토리얼에서 티어, 우선순위 큐, 관련 코드를 다룹니다. 텍스처 VRAM은 150~200MB 미만으로 유지하세요. 이는 RGBA8 2048 텍스처 4~5개 또는 ETC1S 텍스처 30개 정도입니다. 소품은 5,000트라이앵글 미만, 주인공 캐릭터는 30,000~50,000트라이앵글 미만으로 유지하고, 드로우 콜은 수백 회 초반을 목표로 하세요. 소품에는 1024 텍스처를 사용하고 카메라가 가까이 접근하는 대상에만 2048을 사용하세요. Meshopt와 양자화 결과물은 전송 압축에 의존하므로 GLB를 제공할 때 Brotli 또는 gzip을 활성화하세요.
배포 전 검증
파일 크기는 가장 확인하기 쉬운 수치입니다. 결과물을 GLB 뷰어에서 열어 나머지도 확인하세요. Extensions 패널에서는 EXT_meshopt_compression, KHR_draco_mesh_compression, KHR_texture_basisu가 실제로 파일에 포함되었는지 확인할 수 있습니다. Textures 탭은 각 텍스처를 실제 VRAM 사용량이 큰 순서대로 보여주며, 상태 표시줄에는 실시간 드로우 콜과 트라이앵글 수가 표시됩니다. 그런 다음 플레이어가 실제로 보게 될 거리에서 실루엣과 UV 심에 단순화 아티팩트가 없는지 확인하고, 애니메이션을 재생해 결합 과정에서 움직여야 할 부품이 붙어 버리지 않았는지 확인하세요. 원본이 처음부터 GLB가 아니었다면 먼저 FBX나 OBJ를 FBX-GLB 변환기로 변환해 실제로 로드할 파일을 압축하세요.

자주 묻는 질문
GLB 파일 크기를 줄이려면 어떻게 해야 하나요?
gltf-transform inspect를 실행해 텍스처와 지오메트리 중 어느 쪽이 대부분의 용량을 차지하는지 확인하세요. 텍스처가 크다면 1024 또는 2048로 리사이즈하고 WebP나 KTX2로 변환하세요. 지오메트리가 크다면 단순화한 다음 Meshopt나 Draco로 압축하세요. gltf-transform optimize in.glb out.glb --texture-compress webp는 전체 과정을 한 번에 실행하며, 브라우저 기반 GLB 최적화 도구를 사용하면 설치 없이 처리할 수 있습니다.
Draco와 Meshopt 중 어느 것이 더 좋은가요?
대부분의 웹 게임에는 Meshopt가 더 적합합니다. 디코딩 속도가 훨씬 빠르고, 수백 킬로바이트의 WASM 대신 32KB 디코더만 필요하며, Draco가 건너뛰는 애니메이션과 모프 타깃도 압축합니다. Draco는 정적 메시에서 더 작은 파일을 만듭니다. 28MB 테스트 모델에서는 gzip 적용 후 Draco가 2.6MB, Meshopt가 3.3MB였습니다. 또한 PlayCanvas가 지원하는 방식이므로, 에셋이 정적 스캔이고 용량 대부분을 지오메트리가 차지한다면 Draco가 더 유리합니다.
KTX2란 무엇이며 Basis와 어떻게 다른가요?
Basis Universal은 ETC1S와 UASTC라는 두 가지 모드를 제공하는 압축 코덱입니다. KTX2는 Basis로 압축된 텍스처 데이터와 밉맵 및 메타데이터를 담는 Khronos 컨테이너 파일이며, glTF는 KHR_texture_basisu를 통해 이를 참조합니다. 이전 파이프라인에서는 독립된 .basis 파일을 사용했습니다. .ktx2를 사용하세요.
ETC1S와 UASTC 중 무엇을 사용해야 하나요?
베이스 컬러와 가까이서 보이지 않는 모든 텍스처에는 ETC1S를 사용하세요. 파일이 작고 VRAM에서 픽셀당 4비트만 사용합니다. 노멀 맵, 러프니스/메탈니스/오클루전, 주요 캐릭터 텍스처에는 UASTC를 사용하고, 다운로드 용량을 적절하게 유지하도록 Zstandard 슈퍼압축을 활성화하세요. 컬러 텍스처는 sRGB, 데이터 텍스처는 리니어로 지정해야 합니다. 그렇지 않으면 노멀의 셰이딩이 잘못 표시됩니다.
glTF 텍스처를 어떻게 압축하나요?
다운로드 용량을 줄이려면 gltf-transform resize를 실행한 다음 gltf-transform webp를 사용하세요. GPU 메모리를 줄이려면 KTX-Software를 설치한 상태에서 gltf-transform etc1s 또는 uastc를 사용하거나, PNG 파일을 KTX2 압축기에 드롭하세요. 어느 방식을 사용하든 먼저 크기를 제한하세요. 4096 텍스처는 RGBA8에서 VRAM을 89MB나 사용하며, 브라우저로 제공할 이유는 거의 없습니다.
모바일의 three.js에서 GLB가 너무 큰 이유는 무엇인가요?
대개 문제는 파일 크기가 아니라 텍스처 메모리입니다. 2048 RGBA 텍스처 4개는 장면을 그리기도 전에 약 90MB의 VRAM을 사용하며, 스마트폰 브라우저는 사용량이 수백 MB를 넘으면 탭을 종료합니다. KTX2로 변환해 텍스처가 GPU에서도 압축된 상태를 유지하도록 하고, 가능한 경우 1024로 제한하세요. 또한 KTX2Loader.detectSupport(renderer)를 호출해 기기에 맞는 형식으로 트랜스코딩되도록 하세요.
gltfpack은 gltf-transform과 같은 작업을 하나요?
대부분 그렇습니다. gltfpack은 meshoptimizer 프로젝트에서 제공하는 단일 네이티브 바이너리로, 기본적으로 양자화, GPU 캐시를 위한 버텍스 재정렬, 메시 병합, Meshopt 압축을 수행합니다. glTF-Transform은 동일한 작업을 각각 스크립트로 제어할 수 있는 단계로 제공하는 Node 라이브러리이자 CLI이며, gltfpack이 생성하지 못하는 Draco 결과물도 지원합니다. 테스트 파일에서 두 도구의 Meshopt 결과물 크기는 약 10% 이내의 차이를 보였습니다.
관련 콘텐츠
- 웹 게임 에셋 스트리밍 로딩: 방금 줄인 파일을 위한 티어, 우선순위 큐, 진행률 표시줄
- 2026년 웹 게임 기술 스택: API 수준에서 살펴보는 WebGL, WebGPU, Wasm, 에셋 형식
- 무료 3D 모델 사이트: 모델을 구할 수 있는 곳과 모델 용량이 큰 이유
- 최고의 AI 3D 모델 생성기: 생성기의 출력 형식과 메시 밀도
- Three.js와 Babylon.js 비교: 설정 방식은 다르지만 둘 다 Draco, Meshopt, KTX2를 로드
- PlayCanvas와 Three.js 비교: 에셋 파이프라인을 포함한 엔진과 라이브러리 비교