Plataformas distintas, destinos distintos: una guía de selección de compresión
Los cuatro artículos anteriores trataban las herramientas de compresión de vértices y texturas. Pero saber usar las herramientas es una cosa; cuál usar y en qué escenario es otra. Este artículo responde a eso — y aspira a que decidas en cuanto termines de leer.
Tras este artículo deberías poder responder: en qué plataforma corre mi proyecto, el cuello de botella del first paint es descarga o VRAM, y qué esquema deben usar texturas y vértices respectivamente.
Marcar el rumbo: guiado por escenario, no por herramienta
El artículo entero tiene un principio central, uno que la serie no deja de subrayar:
No existe un esquema de compresión «el mejor» — solo el «que mejor encaja con el escenario».
Tres variables que mueven la elección:
- Plataforma/dispositivo: PC de escritorio, navegador móvil, casco de VR, Mini Program — capacidades radicalmente distintas
- Uso: exhibición de una sola vez (página de producto e-commerce) o inmersión larga (juego VR)
- Cuello de botella principal: descarga lenta, VRAM insuficiente o decode que frena el first paint
Piensa primero el cuello de botella y luego vuelve a elegir herramientas. La matriz de abajo congela ese razonamiento.
Matriz central de decisión: plataforma × esquema recomendado
Esta es la tabla más importante del artículo. Por plataforma, da el esquema recomendado para textura y vértice, con razones.
| Plataforma / escenario | Esquema textura | Esquema vértice | Cuello de botella | Razón clave |
|---|---|---|---|---|
| Web escritorio (PC) | KTX2 o WebP | MeshOpt / cuantización | Velocidad de descarga | VRAM amplio; foco en archivos pequeños, carga rápida |
| Web móvil (móvil) | KTX2 (obligatorio) | MeshOpt | VRAM | VRAM del móvil justo; texturas con compresión por bloque obligatoria |
| WebXR / casco VR | KTX2 (obligatorio) | MeshOpt + LOD | VRAM + framerate | Exceso de VRAM crashea; caída de frames da mareo |
| WeChat Mini Program | KTX2 / WebP | MeshOpt / cuant. pura | Paquete + compat. | Tamaño de paquete limitado; evitar decoders pesados |
| Producto e-commerce | WebP (ligero) / KTX2 (preciso) | MeshOpt | Velocidad first paint | Exige apertura instantánea; cambiar tamaño por velocidad |
| Escenas grandes / digital twin | KTX2 (obligatorio) | MeshOpt + Draco + LOD | VRAM + draw calls | Muchas texturas, modelos grandes; comprimir en todo |
Algunos juicios que valen la pena recordar:
- Siempre que el VRAM es el cuello de botella, KTX2 es obligatorio (móvil, VR, escenas grandes)
- Si la descarga es el cuello y el VRAM es amplio, WebP basta (escritorio, e-commerce)
- En entornos sensibles al paquete como Mini Programs, prefiere MeshOpt sobre Draco — decoder más pequeño, mejor compatibilidad
- Considera Draco solo para modelos muy grandes; para la inmensa mayoría de modelos mediano-pequeños MeshOpt es más equilibrado
Formatos de textura comparados en todas las dimensiones
Saber «usa KTX2» no basta. Para los formatos de textura, despliega todas las dimensiones:
| Formato | Tamaño archivo | Uso VRAM | Velocidad subida | Compatibilidad | Calidad | Uso |
|---|---|---|---|---|---|---|
| PNG | Grande | Grande (tras descomp.) | Lenta | Muy amplia | Sin pérdida | Necesita valores exactos/alfa, o fallback legacy |
| JPG | Diminuto | Grande (tras descomp.) | Lenta | Muy amplia | Con pérdida | Color maps, prioridad de red |
| WebP | Muy pequeño | Grande (tras descomp.) | Lenta | Bastante amplia | Alto | Web escritorio, perseguir velocidad de descarga |
| AVIF | Aún más pequeño | Grande (tras descomp.) | Lenta | Progresivo | Alto | Plataformas nuevas, compresión extrema |
| KTX2 (ETC1S) | Pequeño | Diminuto | Rápida | Necesita transcode | Medio (color ok) | Color maps, móvil/VR |
| KTX2 (UASTC) | Medio | Pequeño | Rápida | Necesita transcode | Alto | Normal/data maps |
Nota las tres primeras filas (PNG/JPG/WebP/AVIF) con VRAM «grande» — por muy pequeño en disco, al entrar al VRAM todas se descomprimen a píxeles crudos. Esa es la limitación fundamental de los formatos tradicionales.
Una estrategia mixta es común: los color maps clave usan KTX2 para asegurar VRAM; los maps secundarios (p. ej. un emissive pequeño) usan WebP por comodidad. No tienes que ir a todo KTX2; reparte por cuello de botella.
Diagrama de flujo de decisión: elegir paso a paso
La matriz es el resultado; el diagrama muestra cómo llegar a él.
¿Dónde corre tu proyecto?
│
├─ Web escritorio (VRAM amplio)
│ └─ ¿First paint lento?
│ ├─ Sí → WebP (o AVIF) + MeshOpt [perseguir velocidad de descarga]
│ └─ No, pero muchos modelos → KTX2 + MeshOpt [dejar margen para el futuro]
│
├─ Web móvil / VR / escenas grandes (VRAM justo)
│ └─ Texturas obligatoriamente KTX2 (color ETC1S, datos UASTC)
│ └─ ¿Vértices superdensos?
│ ├─ Sí → + Draco [razón máxima, tolera decode lento]
│ └─ No → + MeshOpt [equilibrado]
│
└─ Mini Program / runtime restringido
└─ ¿Sensible al paquete?
├─ Sí → cuantización pura o MeshOpt + WebP [decoder cero/pequeño]
└─ Ok → MeshOpt + KTX2 [combinación estándar]
Compresión de vértices vs texturas: dónde invertir
Pregunta frecuente: presupuesto limitado, ¿qué optimizar primero? Mira la composición del modelo:
| Rasgo del modelo | Foco de inversión | Razón |
|---|---|---|
| Personaje/producto PBR (muchos maps) | Compresión de texturas | Las texturas son 80 %+; ROI de vértices bajo |
| Modelo CAD/scan (vértices superdensos, pocos maps) | Compresión de vértices | Los vértices son la mayor parte |
| Personaje animado (esqueleto + skinning) | Invierte en ambos, pero vértices priorizar más allá de Draco | Los datos de animación también pesan; Draco es flojo con animación |
| Edificio/escena (grande, maps medios) | Textura + LOD | Las texturas ahorran VRAM; el LOD ahorra draw calls |
Un ranking de retorno aproximado: textura KTX2 > vértice MeshOpt/cuantización > simplificación de geometría (LOD) > vértice Draco. Haz primero lo de mayor retorno.
Estrategia mixta: maps clave KTX2, maps secundarios WebP
No todos los maps merecen comprimirse a KTX2. Un material PBR típico tiene 5-6 maps; comprimir todos a KTX2 es mucho trabajo y a veces innecesario.
Reparto práctico:
- KTX2 obligatorio: albedo (grande, color), normal (sensible a precisión), roughness/metallic (afectan a la iluminación)
- Puede ser WebP/JPG: emissive (normalmente pequeño), AO (frecuencia media-baja), normal de detalle (si lo hay)
Criterio: ¿el map es grande, es detalle de alta frecuencia, se muestrea con frecuencia? Los tres → KTX2; ninguno → formato tradicional más fácil.
Selección automatizada: gltf-transform lo hace de un golpe
El comando optimize de gltf-transform es la bala de plata para la mayoría de escenarios — detecta tipos de textura automáticamente, comprime texturas con la estrategia recomendada y opcionalmente trata vértices.
# Instalar
npm install -g @gltf-transform/cli
# Optimización estándar: textura KTX2 + vértice MeshOpt + desdup
gltf-transform optimize model.glb model-optimized.glb \
--texture-compress basisu \
--meshopt
Referencia de parámetros:
| Parámetro | Efecto | Por defecto |
|---|---|---|
--texture-compress basisu | Comprimir texturas a KTX2 (auto ETC1S/UASTC) | Off |
--meshopt | Activar compresión MeshOpt de vértices | Off |
--simplify | Simplificación de geometría (reduce vértices, con pérdida) | Off |
--weld | Fusionar vértices duplicados | On |
--prune | Eliminar nodos/materiales no usados | On |
Una combinación de «compresión fuerte» para móvil:
gltf-transform optimize model.glb model-mobile.glb \
--texture-compress basisu \
--meshopt \
--simplify --simplify-ratio 0.5 \
--prune --weld
Una combinación «suave» para escritorio (preservar detalle, solo comprimir texturas y vértices):
gltf-transform optimize model.glb model-desktop.glb \
--texture-compress webp \
--meshopt
Envolverlo como script reutilizable
Encapsula lo anterior en un script que saque una versión por plataforma:
// compress.mjs — sacar versiones comprimidas distintas por objetivo
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 = {
// Móvil: KTX2 + MeshOpt + simplificar
mobile: { texture: "basisu", meshopt: true, simplify: 0.5 },
// VR: KTX2 + MeshOpt, sin simplificar (visión cercana en VR)
vr: { texture: "basisu", meshopt: true, simplify: null },
// Escritorio: WebP + MeshOpt, suave
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(); // copia independiente por objetivo
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
# Saca model-mobile.glb / model-vr.glb / model-desktop.glb
En runtime, carga la versión correspondiente por dispositivo (distingue vía UA o detección de capacidad WebGL) para la mejor experiencia de first paint. El próximo artículo lo ata todo en el walkthrough end-to-end.
Chuleta de una línea
- VRAM es el cuello → KTX2, sin elección
- Descarga es el cuello, VRAM amplio → WebP/AVIF también vale
- Sensible al tamaño del decoder → MeshOpt > cuantización pura > Draco
- Modelos muy grandes → solo entonces considera Draco
- Inseguro → ejecuta
gltf-transform optimizede un golpe; si falla, ajusta
Siguiente paso
El marco de selección está listo. El último artículo cierra: partiendo de un modelo real, recorre el flujo completo de export de Blender, compresión de texturas, compresión de vértices y carga en motor, con un script de automatización completo y una chuleta de la serie.