KTX2 na Prática: A Forma Correta de Fazer Compressão de Texturas
O artigo anterior desenrolou os formatos de textura de GPU, Basis Universal e KTX2. A teoria está clara; este é todo prático: como escolher entre ETC1S e UASTC, quais ferramentas usar, quais comandos digitar e como carregar no engine.
Você pode acompanhar e fazer ao mesmo tempo que lê.
Primeiro, a escolha mais importante: ETC1S ou UASTC
O Basis oferece duas codificações intermediárias. Escolha errado e não é "não é bom o suficiente"—seu normal map simplesmente vira lama. Memorize esta tabela:
| ETC1S | UASTC | |
|---|---|---|
| Taxa de compressão | Muito alta (como JPG) | Média (qualidade alta, como PNG) |
| Qualidade | Boa para mapas de cores | Qualidade quase original |
| VRAM (após transcodificação) | Geralmente 4bpp (~1/8 do original) | Geralmente 8bpp (~1/4 do original) |
| Velocidade de codificação | Lenta (nível ajustável) | Mais rápida |
| Usar para | albedo/difuso, emissive | normal, metalness-roughness, mapas de dados |
| Não usar para | normais, imagens que precisam de valores precisos | Mapas de cores (exagero, tamanho fica grande) |
Por que normais não podem usar ETC1S? Porque um normal map armazena vetores de direção, e os canais RGB de cada pixel se restringem mutuamente (comprimento do vetor ≈ 1). ETC1S é uma compressão por blocos projetada para fazer "cores parecerem corretas"; ela não é sensível à precisão de canal único, então após a compressão a direção do vetor se desvia e a iluminação imediatamente fica errada—especialmente posições de destaque e detalhes de alta frequência. UASTC preserva valores numéricos melhor e se sustenta nessa demanda de precisão.
Regras práticas:
- Mapas de cores (albedo, emissive) → ETC1S
- Mapas de dados (normal, roughness, metallic, AO, thickness) → UASTC
- Não tem certeza mas quer economizar tamanho → tente ETC1S primeiro; se um close-up ficar borrado, mude para UASTC
Uma imagem, quatro formatos comparados
Usando um mapa albedo de 2048×2048 como linha de base (valores são números típicos da comunidade, apenas para referência):
| Formato | Tamanho no disco | Uso de VRAM (com mipmaps) | Upload para GPU | Cross-platform |
|---|---|---|---|---|
| PNG | ~5MB | ~22MB | Lento | ✅ |
| WebP | ~1MB | ~22MB | Lento | ✅ |
| KTX2 (ETC1S) | ~0.5-0.8MB | ~2.8MB | Rápido | ✅ |
| KTX2 (UASTC) | ~3-4MB | ~5.6MB | Rápido | ✅ |
Note que o uso de VRAM do WebP é o mesmo do PNG—é só pequeno no disco; na VRAM ele ainda descomprime para pixels brutos. O KTX2 com ETC1S reduz tanto o disco quanto a VRAM muito baixo de uma vez—é isso que o torna valioso.
Cadeia de ferramentas: todos os caminhos levam lá
Há mais de uma ferramenta para comprimir KTX2, ordenadas por "facilidade de obter":
1. toktx (oficial, mais poderoso)
A ferramenta oficial do Khronos, com mais parâmetros, adequada para processar texturas individualmente.
# Convert PNG to an ETC1S-encoded KTX2
toktx --bcmp --uastc 0 albedo.ktx2 albedo.png
# Convert PNG to a UASTC-encoded KTX2
toktx --uastc 1 normal.ktx2 normal.png
Parâmetros comuns:
# ETC1S + quality level (1-255, default 128; higher = better quality and larger size)
toktx --bcmp --uastc 0 --qlevel 200 albedo.ktx2 albedo.png
# UASTC + supercompression (Zstandard, further shrinks disk size)
toktx --uastc 1 --zcmp 19 normal.ktx2 normal.png
# Auto-generate mipmaps (strongly recommended)
toktx --bcmp --genmipmap albedo.ktx2 albedo.png
# Specify sRGB color space (required for color maps)
toktx --bcmp --srgb albedo.ktx2 albedo.png
--bcmpé a chave do modo ETC1S (modo base do Basis Universal), e--uastc 1é o modo UASTC. Os dois são mutuamente exclusivos.
2. gltf-transform (mais fácil, altamente recomendado)
Se você tem um modelo glTF/GLB inteiro, use gltf-transform para trocar todas as suas texturas por KTX2 em um único comando, escolhendo automaticamente ETC1S/UASTC pela finalidade da textura.
# Install
npm install -g @gltf-transform/cli
# One-shot compress the whole model
gltf-transform optimize model.glb model-optimized.glb \
--texture-compress basisu
Ele julga internamente a finalidade da textura: tipos de cores usam ETC1S, tipos de dados usam UASTC, e escreve a extensão KHR_texture_basisu automaticamente. Esta é a melhor escolha para 90% dos casos—não precisa digitar toktx manualmente um por um.
3. Ferramentas online (mais rápido para começar)
Quando não quer configurar um ambiente, use uma ferramenta de navegador: gltf.report (gltf-transform online), KTX2 Converter, etc. Envie, baixe, pronto. Bom para experimentos iniciais ou tarefas pontuais.
Fluxo completo: da origem à produção
Aqui está o fluxo padrão (diagrama de fluxo):
Arquivo de origem (PNG/JPG/PSD/TGA)
│
├── [modelo inteiro] gltf-transform optimize model.glb → detectar tipo de textura automaticamente
│ └─ mapas de cores → ETC1S
│ └─ mapas de dados → UASTC
│ └─ escreve extensão KHR_texture_basisu
│
└── [textura única] toktx → especificar manualmente ETC1S/UASTC + espaço de cores + mipmap
│
▼
KTX2 / GLB comprimido
│
▼
Carregamento no engine (Three.js / Babylon.js) ── transcodificação em tempo real → formato nativo da GPU
Carregando KTX2 no Three.js
O Three.js suporta KTX2 nativamente desde a r129. Anexe um KTX2Loader—apontando para o wasm do transcodificador Basis e sondando o suporte da GPU—ao GLTFLoader; qualquer glTF com texturas KTX2 então transcodifica automaticamente na hora do carregamento.
const ktx2Loader = new KTX2Loader().setTranscoderPath("/basis/").detectSupport(renderer);
gltfLoader.setKTX2Loader(ktx2Loader); // also attach DRACOLoader / MeshoptDecoder if the model uses them
detectSupport(renderer) é obrigatório—ele decide para qual formato nativo transcodificar. E defina as mapas de cores com texture.colorSpace = THREE.SRGBColorSpace; pular isso é o bug clássico de "tudo parece cinza" (mapas de dados como normal/roughness ficam em linear).
Carregando KTX2 no Babylon.js
Babylon é ainda mais fácil—GLTFFileLoader habilita KHR_texture_basisu por padrão e busca automaticamente o transcodificador Basis de uma CDN, então glTFs com texturas KTX2 simplesmente funcionam. Para ambientes offline/intranet, configure manualmente BASISFileLoader.TranscoderModule.
Ajuste de parâmetros de compressão: equilibrando qualidade e tamanho
O parâmetro principal do ETC1S é --qlevel (1-255). Como ele afeta o resultado:
| qlevel | Tamanho | Qualidade | Tempo de codificação | Caso de uso |
|---|---|---|---|---|
| 128 (padrão) | Pequeno | Adequada | Médio | Maioria dos casos |
| 200-255 | Maior | Quase sem perdas | Longa (várias vezes) | Requisitos de alta qualidade |
| 60-100 | Muito pequeno | Bloqueio visível | Rápida | Texturas distantes/pequenas |
O tamanho do UASTC é relativamente fixo; você ajusta principalmente o tamanho no disco com --zcmp (supercompressão Zstandard), que não afeta a VRAM (continua 8bpp após descompressão).
Ordem recomendada de ajuste:
- Primeiro comprima uma vez com os padrões e verifique tamanho e qualidade
- Não satisfeito → ajuste
--qlevel(ETC1S) ou adicione--zcmp(UASTC) - Normal map ficou borrado → confirme que está usando UASTC, não ETC1S
- Cores parecem escuras → verifique as configurações de espaço de cores (flag sRGB, colorSpace no engine)
Solução de problemas comuns
Falha na transcodificação / erro de carregamento
- Verifique se o caminho do wasm do transcodificador está correto (Three.js precisa de
setTranscoderPath) - Verifique se a versão do seu engine suporta a versão atual do KTX2 (codificações Basis mais antigas não são suportadas por transcodificadores mais novos)
- O console geralmente tem um erro específico; busque por palavra-chave
Cores muito escuras / muito claras
- Uma mapa de cores (albedo) não foi definida como sRGB, ou foi definida ao contrário
- Você esqueceu
--srgbno toktx (mapas de cores precisam dele) - Um mapa de dados (normal) recebeu sRGB por engano
Mipmaps ausentes, cintilação à distância
- A compressão não adicionou
--genmipmap - O engine não habilitou
texture.generateMipmaps(no Three.js, KTX2 segue o arquivo por padrão, mas ominFilterdo material ainda precisa de um modo de mipmap)
Direção da normal errada em close-up
- O normal map usou ETC1S; mude para UASTC
- Confirme que o normal map é estilo OpenGL (canal verde para cima); estilo DirectX precisa do canal G invertido em alguns engines
Arquivo ficou maior
- Texturas pequenas (< 128×128) não valem o KTX2—compressão por blocos tem sobrecarga fixa e preenche um bloco inteiro
- Não use KTX2 em textura de cor sólida; usar um valor de cor no material é mais barato
Próximo passo
Isso basicamente encerra a compressão de texturas. Mas "saber como usar as ferramentas" não é o mesmo que "usar as ferramentas certas"—o próximo artigo junta todo o conhecimento dos quatro anteriores em um framework de seleção: desktop, mobile, VR, Mini Programas—exatamente qual combinação cada cenário deve usar.