Any3DAny3D
·Any3D Team

Plataformas distintas, destinos distintos: una guía de selección de compresión

3d-compressiontexture-compressionvertex-compressionoptimizationpipeline

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:

  1. Plataforma/dispositivo: PC de escritorio, navegador móvil, casco de VR, Mini Program — capacidades radicalmente distintas
  2. Uso: exhibición de una sola vez (página de producto e-commerce) o inmersión larga (juego VR)
  3. 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 / escenarioEsquema texturaEsquema vérticeCuello de botellaRazón clave
Web escritorio (PC)KTX2 o WebPMeshOpt / cuantizaciónVelocidad de descargaVRAM amplio; foco en archivos pequeños, carga rápida
Web móvil (móvil)KTX2 (obligatorio)MeshOptVRAMVRAM del móvil justo; texturas con compresión por bloque obligatoria
WebXR / casco VRKTX2 (obligatorio)MeshOpt + LODVRAM + framerateExceso de VRAM crashea; caída de frames da mareo
WeChat Mini ProgramKTX2 / WebPMeshOpt / cuant. puraPaquete + compat.Tamaño de paquete limitado; evitar decoders pesados
Producto e-commerceWebP (ligero) / KTX2 (preciso)MeshOptVelocidad first paintExige apertura instantánea; cambiar tamaño por velocidad
Escenas grandes / digital twinKTX2 (obligatorio)MeshOpt + Draco + LODVRAM + draw callsMuchas 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:

FormatoTamaño archivoUso VRAMVelocidad subidaCompatibilidadCalidadUso
PNGGrandeGrande (tras descomp.)LentaMuy ampliaSin pérdidaNecesita valores exactos/alfa, o fallback legacy
JPGDiminutoGrande (tras descomp.)LentaMuy ampliaCon pérdidaColor maps, prioridad de red
WebPMuy pequeñoGrande (tras descomp.)LentaBastante ampliaAltoWeb escritorio, perseguir velocidad de descarga
AVIFAún más pequeñoGrande (tras descomp.)LentaProgresivoAltoPlataformas nuevas, compresión extrema
KTX2 (ETC1S)PequeñoDiminutoRápidaNecesita transcodeMedio (color ok)Color maps, móvil/VR
KTX2 (UASTC)MedioPequeñoRápidaNecesita transcodeAltoNormal/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 modeloFoco de inversiónRazón
Personaje/producto PBR (muchos maps)Compresión de texturasLas texturas son 80 %+; ROI de vértices bajo
Modelo CAD/scan (vértices superdensos, pocos maps)Compresión de vérticesLos vértices son la mayor parte
Personaje animado (esqueleto + skinning)Invierte en ambos, pero vértices priorizar más allá de DracoLos datos de animación también pesan; Draco es flojo con animación
Edificio/escena (grande, maps medios)Textura + LODLas 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ámetroEfectoPor defecto
--texture-compress basisuComprimir texturas a KTX2 (auto ETC1S/UASTC)Off
--meshoptActivar compresión MeshOpt de vérticesOff
--simplifySimplificación de geometría (reduce vértices, con pérdida)Off
--weldFusionar vértices duplicadosOn
--pruneEliminar nodos/materiales no usadosOn

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 optimize de 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.

Apóyanos