Skip to content

Texture Optimization

Handles standalone image files (loose textures not embedded in GLB) — for example, a batch of PNG/JPG textures exported from your modeling software.

How is this different from "Texture Settings" in Compression Optimization?

  • Texture Optimization tab: processes standalone image files on disk (.png / .jpg / .webp) and outputs standalone image files
  • Compression Optimization → Texture Settings: processes textures embedded inside GLB files and still outputs GLB

To compress textures embedded in a GLB, go to Model Compression → Texture Settings — you don't need this tab for that.

Usage

  1. Select image files (PNG / JPEG / WebP) or a folder (batch processing)
  2. Pick the output format: JPEG (compatible) / WebP (~30% smaller) / KTX2 (GPU-native)
  3. Set the max edge length (larger images are scaled down proportionally; 2048 recommended; leave empty for no limit)
  4. Click "Start Optimize"
Texture optimization settings

Output is saved next to the original file with an _optimized suffix; KTX2 output is named {original}_ktx2.ktx2.

KTX2 Parameters

ParameterDescription
Compression modeETC1S (small size, lossy) / UASTC (high quality, near-lossless)
Quality1–255 in ETC1S mode; 96 recommended (smaller) or 128 (balanced); higher = better quality but larger files
Mipmap chainDisabling saves ~33% size; when disabled, set generateMipmaps: false manually in Three.js

Which mode should I pick?

Use ETC1S for color maps (albedo / diffuse) — smaller files. Use UASTC for detail-critical textures like normal maps and specular maps.

When mipmaps are off, update your loader code

With mipmaps disabled, Three.js will still try to generate them by default, but KTX2 textures cannot be regenerated dynamically — this causes render warnings or visual glitches. Set it manually after loading:

js
texture.generateMipmaps = false
texture.minFilter = THREE.LinearFilter  // or NearestFilter

Loading KTX2 in Three.js

Prerequisites

KTX2 is a GPU-native format. Three.js needs an extra decoder (Basis Universal Transcoder) to load it. This is not a Zipoly issue — it is a universal requirement of the KTX2 toolchain.

js
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js'
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'

// renderer is your THREE.WebGLRenderer instance
const ktx2Loader = new KTX2Loader()
// Recommended: copy the transcoder files into your project's public folder (no external CDN dependency)
// cp node_modules/three/examples/jsm/libs/basis public/basis -r
ktx2Loader.setTranscoderPath('/basis/')
ktx2Loader.detectSupport(renderer) // picks the best sub-format for your GPU

// Load a GLB that contains KTX2 textures
const loader = new GLTFLoader()
loader.setKTX2Loader(ktx2Loader)
loader.load('model.glb', gltf => scene.add(gltf.scene))

// Load a standalone KTX2 file (not inside a GLB)
const texture = await ktx2Loader.loadAsync('texture_ktx2.ktx2')
material.map = texture
material.needsUpdate = true

KTX2 is not supported by Babylon.js or model-viewer

The KTX2 texture format (KHR_texture_basisu extension) is currently fully supported only in Three.js. If your project uses Babylon.js or model-viewer, choose JPEG or WebP instead.

Built for Web3D developers