플랫폼이 다르면 운명도 다르다: 압축 방안 선정 가이드
앞선 4편은 각각 정점 압축과 텍스처 압축의 도구를 다뤘습니다. 하지만 도구를 쓸 줄 아는 것과, 어떤 것을, 어떤 씬에서 쓸지 는 별개의 문제입니다. 이 글이 그 질문에 답합니다 — 그리고 다 읽으면 바로 결정할 수 있게끔 노력했습니다.
이 글을 읽고 나면 답할 수 있어야 합니다: 내 프로젝트는 어떤 플랫폼에서 도는가, 첫 화면의 병목은 다운로드인가 VRAM인가, 텍스처와 정점은 각각 어떤 방안을 써야 하는가.
방침 정하기: 씬 주도, 도구 주도가 아니다
이 글의 핵심 원칙은 하나뿐이며, 시리즈 전체가 반복해 강조한 것입니다:
"가장 좋은" 압축 방안은 없고, "가장 씬에 맞는" 방안만 있습니다.
선택을 좌우하는 세 변수:
- 플랫폼/기기: 데스크톱 PC, 모바일 브라우저, VR 헤드셋, 미니프로그램 — 능력 차이가 역력
- 사용 방식: 일회성 표시(이커머스 상품 페이지)인가, 장시간 몰입(VR 게임)인가
- 주요 병목: 다운로드 속도가 느린 건가, VRAM이 부족한 건가, 첫 화면 디코딩이 걸리는 건가
먼저 병목을 생각하고, 다시 도구를 고르러 돌아옵시다. 아래 매트릭스가 그 사고방식을 고정한 것입니다.
핵심 의사결정 매트릭스: 플랫폼 × 추천 방안
이 글에서 가장 중요한 표입니다. 플랫폼별로 텍스처와 정점 각각의 추천 방안과 이유를 줍니다.
| 플랫폼 / 씬 | 텍스처 방안 | 정점 방안 | 주요 병목 | 핵심 이유 |
|---|---|---|---|---|
| 데스크톱 웹(PC 브라우저) | KTX2 또는 WebP | MeshOpt / 양자화 | 다운로드 속도 | VRAM 여유, 핵심은 작고 빠르게 |
| 모바일 웹(스마트폰 브라우저) | KTX2(필수) | MeshOpt | VRAM | 폰 VRAM이 타이트, 텍스처는 블록 압축 필수 |
| WebXR / VR 헤드셋 | KTX2(필수) | MeshOpt + LOD | VRAM + 프레임레이트 | VRAM 폭발로 크래시, 프레임 드롭으로 멀미 |
| 위챗 미니프로그램 | KTX2 / WebP | MeshOpt / 순수 양자화 | 패키지 + 호환성 | 패키지 크기 제한, 무거운 디코더 회피 |
| 이커머스 상품 표시 | WebP(경량) / KTX2(정밀) | MeshOpt | 첫 화면 속도 | 즉시 열림 요구, 크기로 속도를 산다 |
| 대형 씬 / 디지털 트윈 | KTX2(필수) | MeshOpt + Draco + LOD | VRAM + 드로 콜 | 텍스처 많고, 모델 큼, 전방위 압축 |
기억할 만한 판단:
- VRAM이 병목이면 KTX2는 필수(모바일, VR, 대형 씬 모두 해당)
- 다운로드가 병목이고 VRAM에 여유가 있으면 WebP도 충분(데스크톱, 이커머스)
- 미니프로그램 등 패키지에 민감한 환경에서는 Draco보다 MeshOpt 우선 — 디코더가 작고 호환성도 좋음
- 초대형 모델에서만 Draco 검토, 압도적 다수의 중소 모델에서는 MeshOpt가 더 밸런스 좋음
텍스처 포맷 전 차원 비교
"KTX2를 쓴다"만으로는 부족합니다. 텍스처 포맷에 대해 모든 차원을 펼쳐 봅시다:
| 포맷 | 파일 크기 | VRAM 사용량 | 업로드 속도 | 호환성 | 화질 | 적합 용도 |
|---|---|---|---|---|---|---|
| PNG | 큼 | 큼(해제 후) | 느림 | 극히 넓음 | 무손실 | 정확한 수치/알파 필요, 구플랫폼 폴백 |
| JPG | 극히 작음 | 큼(해제 후) | 느림 | 극히 넓음 | 손실 | 컬러 맵, 네트워크 우선 |
| WebP | 매우 작음 | 큼(해제 후) | 느림 | 비교적 넓음 | 높음 | 데스크톱 웹, 다운로드 속도 추구 |
| AVIF | 더 작음 | 큼(해제 후) | 느림 | 점진적 | 높음 | 새 플랫폼, 극한 압축 |
| KTX2 (ETC1S) | 작음 | 극소 | 빠름 | 트랜스코드 필요 | 중간(컬러는 충분) | 컬러 맵, 모바일/VR |
| KTX2 (UASTC) | 중간 | 소 | 빠름 | 트랜스코드 필요 | 높음 | 노멀/데이터 맵 |
처음 세 줄(PNG/JPG/WebP/AVIF)의 VRAM 사용량이 모두 "큼"인 걸 주의하세요 — 디스크가 아무리 작아도 VRAM에 들어가면 원래의 raw pixel로 해제됩니다. 이게 전통 포맷의 근본적 한계입니다.
혼합 전략은 흔합니다: 핵심 컬러 맵은 KTX2로 VRAM을 확보하고, 부차적 맵(작은 emissive 같은)은 WebP로 간편하게. 전부 KTX2로 일도양단할 필요 없이, 병목으로 배분합니다.
의사결정 플로우차트: 단계별로 고르기
매트릭스는 결과, 플로우차트는 어떻게 그 결과에 이르는지 보여줍니다.
당신의 프로젝트는 어디서 도는가?
│
├─ 데스크톱 웹(VRAM 여유)
│ └─ 첫 화면이 느린가?
│ ├─ 느림 → WebP(또는 AVIF) + MeshOpt [다운로드 속도 추구]
│ └─ 안 느리지만 모델이 많음 → KTX2 + MeshOpt [미래에 여유 확보]
│
├─ 모바일 웹 / VR / 대형 씬(VRAM 타이트)
│ └─ 텍스처는 필수 KTX2(컬러 ETC1S, 데이터 UASTC)
│ └─ 모델 정점이 초밀집?
│ ├─ 예 → + Draco [극한 압축, 느린 해독 감내]
│ └─ 아니오 → + MeshOpt [밸런스]
│
└─ 미니프로그램 / 제한적 런타임
└─ 패키지에 민감?
├─ 민감 → 순수 양자화 또는 MeshOpt + WebP [디코더 제로/소형]
└─ 괜찮음 → MeshOpt + KTX2 [일반 조합]
정점 vs 텍스처 압축: 어디에 투자할까
자주 묻는 질문: 예산이 제한적일 때 어느 쪽을 먼저 최적화할까? 모델의 구성을 보세요:
| 모델 특징 | 투자 중점 | 이유 |
|---|---|---|
| PBR 캐릭터/제품(맵 많음) | 텍스처 압축 | 텍스처가 80%+, 정점의 ROI 낮음 |
| CAD/스캔 모델(정점 초밀집, 맵 적음) | 정점 압축 | 정점이 주 용량 |
| 애니메이션 캐릭터(스켈레톤 + 스키닝) | 양쪽 모두, 단 정점은 Draco 외 우선 | 애니메이션 데이터도 용량, Draco는 애니메이션에 약함 |
| 건축/씬(큼, 중간 정도 맵) | 텍스처 + LOD | 텍스처로 VRAM 절약, LOD로 드로 콜 절약 |
수익의 대략적 순위: 텍스처 KTX2 > 정점 MeshOpt/양자화 > 지오메트리 단순화(LOD) > 정점 Draco. 수익 높은 것부터 먼저.
혼합 전략: 핵심 맵은 KTX2, 부차 맵은 WebP
모든 맵을 KTX2로 압축할 가치가 있는 건 아닙니다. 전형적 PBR 머티리얼은 맵 5-6장을 갖고, 전부 KTX2로 하는 건 공수가 크고 때론 불필요합니다.
실용적 분법:
- 필수 KTX2: albedo(큼, 컬러), normal(정밀도 민감), roughness/metallic(조명에 영향)
- WebP/JPG 가능: emissive(보통 작음), AO(중저주파), 디테일 노멀(있다면)
판단 기준: 맵이 큰가, 고주파 디테일인가, 빈번히 샘플링되는가. 셋 다 해당 → KTX2; 어느 것도 아니면 → 전통 포맷이 편함.
자동 선정: gltf-transform 한 방
gltf-transform의 optimize 명령은 대부분 씬의 은탄환 — 텍스처 타입을 자동 판단하고 추천 전략으로 텍스처를 압축하며, 선택적으로 정점도 처리합니다.
# 설치
npm install -g @gltf-transform/cli
# 표준 최적화: 텍스처 KTX2 + 정점 MeshOpt + 중복 제거
gltf-transform optimize model.glb model-optimized.glb \
--texture-compress basisu \
--meshopt
파라미터 설명:
| 파라미터 | 효과 | 기본 |
|---|---|---|
--texture-compress basisu | 텍스처를 KTX2로 압축(ETC1S/UASTC 자동 선택) | 끔 |
--meshopt | 정점에 MeshOpt 압축 활성화 | 끔 |
--simplify | 지오메트리 단순화(정점 감소, 손실) | 끔 |
--weld | 중복 정점 병합 | 켬 |
--prune | 미사용 노드/머티리얼 제거 | 켬 |
모바일용 "강력 압축" 조합:
gltf-transform optimize model.glb model-mobile.glb \
--texture-compress basisu \
--meshopt \
--simplify --simplify-ratio 0.5 \
--prune --weld
데스크톱용 "마일드" 조합(디테일 보존, 텍스처와 정점만 압축):
gltf-transform optimize model.glb model-desktop.glb \
--texture-compress webp \
--meshopt
재사용 가능한 스크립트로
위 내용을 플랫폼별 버전을 출력하는 스크립트로 묶습니다:
// compress.mjs —— target별로 다른 압축 버전 출력
import { optimize } from "@gltf-transform/functions";
import { NodeIO } from "@gltf-transform/core";
import { KHRONOS_EXTENSIONS } from "@gltf-transform/extensions";
const io = new NodeIO().registerExtensions(KHRONOS_EXTENSIONS);
const targets = {
// 모바일: KTX2 + MeshOpt + 단순화
mobile: { texture: "basisu", meshopt: true, simplify: 0.5 },
// VR: KTX2 + MeshOpt, 단순화 없음(VR 근거리 시청)
vr: { texture: "basisu", meshopt: true, simplify: null },
// 데스크톱: WebP + MeshOpt, 마일드
desktop: { texture: "webp", meshopt: true, simplify: null },
};
const input = process.argv[2];
const doc = await io.read(input);
for (const [name, cfg] of Object.entries(targets)) {
const out = doc.clone(); // 각 타깃 독립 사본
await optimize(out, {
textureCompression: cfg.texture,
meshCompression: cfg.meshopt ? "meshopt" : null,
simplify: cfg.simplify != null ? { ratio: cfg.simplify } : null,
});
await io.write(`model-${name}.glb`, out);
console.log(`✓ model-${name}.glb`);
}
node compress.mjs model.glb
# model-mobile.glb / model-vr.glb / model-desktop.glb 출력
런타임에 기기별로 대응 버전을 로드(UA 또는 WebGL 능력 탐지로 구분)하면 첫 화면 경험이 최적입니다. 다음 글의 엔드투엔드 실전에서 이걸 완전히 이어 붙입니다.
한 줄 메모
- VRAM이 병목 → KTX2, 선택 여지 없음
- 다운로드가 병목, VRAM 여유 → WebP/AVIF도 가능
- 디코더 크기에 민감 → MeshOpt > 순수 양자화 > Draco
- 초대형 모델 → 그때만 Draco 검토
- 확신 없음 →
gltf-transform optimize한 방 실행, 틀리면 조정
다음 단계
선정 프레임워크가 갖춰졌습니다. 마지막 글로 마무리합니다: 실제 모델에서 출발해, Blender 내보내기, 텍스처 압축, 정점 압축, 엔진 로드의 전체 흐름을 걷고, 완전한 자동화 스크립트와 시리즈 치트시트를 붙입니다.