Any3DAny3D
·Any3D Team

플랫폼이 다르면 운명도 다르다: 압축 방안 선정 가이드

3d-compressiontexture-compressionvertex-compressionoptimizationpipeline

앞선 4편은 각각 정점 압축과 텍스처 압축의 도구를 다뤘습니다. 하지만 도구를 쓸 줄 아는 것과, 어떤 것을, 어떤 씬에서 쓸지 는 별개의 문제입니다. 이 글이 그 질문에 답합니다 — 그리고 다 읽으면 바로 결정할 수 있게끔 노력했습니다.

이 글을 읽고 나면 답할 수 있어야 합니다: 내 프로젝트는 어떤 플랫폼에서 도는가, 첫 화면의 병목은 다운로드인가 VRAM인가, 텍스처와 정점은 각각 어떤 방안을 써야 하는가.

방침 정하기: 씬 주도, 도구 주도가 아니다

이 글의 핵심 원칙은 하나뿐이며, 시리즈 전체가 반복해 강조한 것입니다:

"가장 좋은" 압축 방안은 없고, "가장 씬에 맞는" 방안만 있습니다.

선택을 좌우하는 세 변수:

  1. 플랫폼/기기: 데스크톱 PC, 모바일 브라우저, VR 헤드셋, 미니프로그램 — 능력 차이가 역력
  2. 사용 방식: 일회성 표시(이커머스 상품 페이지)인가, 장시간 몰입(VR 게임)인가
  3. 주요 병목: 다운로드 속도가 느린 건가, VRAM이 부족한 건가, 첫 화면 디코딩이 걸리는 건가

먼저 병목을 생각하고, 다시 도구를 고르러 돌아옵시다. 아래 매트릭스가 그 사고방식을 고정한 것입니다.

핵심 의사결정 매트릭스: 플랫폼 × 추천 방안

이 글에서 가장 중요한 표입니다. 플랫폼별로 텍스처와 정점 각각의 추천 방안과 이유를 줍니다.

플랫폼 / 씬텍스처 방안정점 방안주요 병목핵심 이유
데스크톱 웹(PC 브라우저)KTX2 또는 WebPMeshOpt / 양자화다운로드 속도VRAM 여유, 핵심은 작고 빠르게
모바일 웹(스마트폰 브라우저)KTX2(필수)MeshOptVRAM폰 VRAM이 타이트, 텍스처는 블록 압축 필수
WebXR / VR 헤드셋KTX2(필수)MeshOpt + LODVRAM + 프레임레이트VRAM 폭발로 크래시, 프레임 드롭으로 멀미
위챗 미니프로그램KTX2 / WebPMeshOpt / 순수 양자화패키지 + 호환성패키지 크기 제한, 무거운 디코더 회피
이커머스 상품 표시WebP(경량) / KTX2(정밀)MeshOpt첫 화면 속도즉시 열림 요구, 크기로 속도를 산다
대형 씬 / 디지털 트윈KTX2(필수)MeshOpt + Draco + LODVRAM + 드로 콜텍스처 많고, 모델 큼, 전방위 압축

기억할 만한 판단:

  • 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-transformoptimize 명령은 대부분 씬의 은탄환 — 텍스처 타입을 자동 판단하고 추천 전략으로 텍스처를 압축하며, 선택적으로 정점도 처리합니다.

# 설치
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 내보내기, 텍스처 압축, 정점 압축, 엔진 로드의 전체 흐름을 걷고, 완전한 자동화 스크립트와 시리즈 치트시트를 붙입니다.

후원하기