← Back to Blog tutorials

Which engines actually support KTX2-compressed GLB textures

By BitSoul Team9/16/20265 min read4 views
Which engines actually support KTX2-compressed GLB textures

You compress a GLB's textures to KTX2 to cut download size, drop it into your engine, and half the materials come back grey or missing. The glTF extension that makes this possible — `KHR_texture_basisu` — is the same file either way. What differs is whether your engine's importer actually knows how to transcode it. Right now Unity, Godot and Unreal Engine 5 sit at three different points on that spectrum, and picking the wrong one to assume support from is what breaks the import, not the texture itself.

Where KTX2 support actually stands per engine

Where KTX2 support actually stands per engine — illustrated

KTX2 is a GPU-ready container format, and Basis Universal is the supercompression inside it — textures ship at roughly JPEG-sized payloads, then transcode at load time into whatever block-compressed format your platform's GPU actually wants (BC7, ASTC, ETC2). The `KHR_texture_basisu` extension just tells a glTF file "this texture is one of those." Whether that's useful depends entirely on whether the engine reading the file bothered to implement the transcode step.

It's worth the trouble chasing down: textures are routinely the single largest contributor to both download size and runtime memory on a model, bigger than geometry in most game-ready assets. Getting the compression side right has an outsized effect on load times and mobile memory budgets compared to shaving triangles.

Unity doesn't import glTF natively at all — it goes through the GLTFast package, and GLTFast's companion KtxUnity package has handled Basis Universal transcoding since roughly the 2022 LTS era. Godot's support is newer and landed as its own dedicated engine change, not a bundled default from day one. Unreal's Interchange glTF path doesn't list `KHR_texture_basisu` among its documented supported extensions, so treat it as the one to verify yourself before you assume anything.

What clears vs breaks in practice

| Engine | KTX2 / `KHR_texture_basisu` | What that means for you |
|---|---|---|
| Unity (via GLTFast + KtxUnity) | Documented support since ~2022 LTS | Works once the companion package is installed; skip it and KTX2 textures silently fail to show |
| Godot 4.x | Added via a dedicated engine PR, still maturing | Works on current stable builds, but has a known crash on "Embed as Basis Universal" with a missing texture — test your exact version |
| Unreal Engine 5 (Interchange) | Not documented as supported | Don't assume transcoding; standard PNG/JPG-sourced textures are the safe default until you've verified otherwise |

Our Police Car ships at full cinematic resolution — 1,894,964 triangles across 11 separately textured parts, 57.8 MB as a GLB with standard textures, no KTX2 involved. Run that same texture set through Basis Universal and the download shrinks toward JPEG territory; the triangle count doesn't move at all, because compression here is a texture-pipeline decision, not a modeling one. A free account's two monthly downloads cover pulling a model like this to test your own pipeline against it; commercial use is included with paid memberships — see pricing for the tiers.

Checking your GLB before you ship it

Checking your GLB before you ship it — illustrated

Don't guess from the file extension — a `.glb` tells you nothing about what's inside its textures. glTF-Transform's `inspect` command reads the actual contents and lists every extension and image format the file uses, KTX2 included:

```bash
npx @gltf-transform/cli inspect police-car.glb
```

Run it before an import you're unsure about, not after materials come back blank. If `KHR_texture_basisu` shows up in the extensions list and you're targeting Unreal, that's your answer before you've wasted a re-import cycle chasing a "missing texture" bug that's really a missing decoder.

BitSoul's own Unity, Unreal, Godot and Blender plugins hand off to each engine's standard glTF and texture path underneath — they don't add their own transcoder, so the same per-engine KTX2 gap applies whether you pull a GLB in through a plugin or drag it in raw.

Falling back when an engine can't transcode it

When the target engine can't be trusted with `KHR_texture_basisu`, decompress back to plain images rather than debugging a transcoder that isn't there:

```bash
npx @gltf-transform/cli ktxdecompress police-car.glb police-car-fallback.glb
```

That rewrites every KTX2/Basis texture in the file as standard PNG data, at the cost of the smaller download you were compressing for in the first place. It's the right trade for an engine that doesn't transcode; it's wasted effort for one that does, which is why the inspect step above comes first, not after.

Going the other direction — compressing a plain-texture GLB down for a Unity or Godot target that does transcode — means picking a Basis mode instead of just accepting a default:

```bash
npx @gltf-transform/cli uastc police-car.glb police-car-ktx2.glb --level 4 --rdo --rdo-lambda 4
```

UASTC keeps more quality at a bigger size; swap in the `etc1s` command instead of `uastc` when the target is a smaller download and you can tolerate more compression artifacting. Neither mode is universally "correct" — it's a quality-versus-size call per texture set, not a setting you pick once for a whole project.

Gotchas

Basis Universal isn't a good fit for every texture type in the first place. It's tuned for correlated color data — base color and emissive maps — and compresses independent-channel data like normal maps and packed ORM maps noticeably worse, so compressing everything uniformly can cost you more visual quality than the download savings are worth. Our ORM-packing writeup covers a related engine-support gap on packed channels specifically — same category of problem, different extension.

Godot's Basis Universal path is recent enough that behavior can vary meaningfully between point releases, not just major versions — pin your export template version, not just "Godot 4."

Generate mipmaps before encoding to UASTC or ETC1S, not after. Letting an engine build mips from an already-transcoded texture at runtime is a common, easy-to-miss source of blurrier results on mobile than the same texture gets on desktop — the fix is ordering the pipeline correctly, not raising the compression quality setting.

If you're already compressing geometry with Draco on the same GLB, check how engine support for that extension breaks down too before assuming a green light on one compression extension means anything about the other — they're independent decisions with independent support matrices, and an engine that transcodes KTX2 fine can still choke on Draco-compressed geometry in the same file.

---

*This post is part of the Ultimate Guide to Free 3D Game Assets — BitSoul's complete reference for formats, texturing, rigging, optimization, and engine integration.*

Tags: texturing optimization game-assets 3d-models pbr tutorials

Skip the modelling — download it instead

A free BitSoul account gets you 2 models every month plus 25 AI Engine credits to generate one of your own, no card required. Clean topology, PBR textures, and GLB downloads that drop straight into Unreal, Unity, Godot or Blender — OBJ and 3D-printable STL export come with any purchase or paid plan.

Browse 1051 models — from $4.99 → or start free (2 downloads a month)