The 3D Handbook
Topic

Texture formats, compression and mipmaps

How game engines store textures on the GPU; the BCn family (BC1, BC3, BC4, BC5, BC7) on desktop and console, ASTC and ETC2 on mobile, normal map compression, sRGB flags, mipmaps and power-of-two sizes, texture streaming, memory arithmetic and Unreal's texture groups.

texturingoptimisationperformanceengines

A GPU does not read PNG or JPEG files. Engines convert every texture to a block-compressed format that the graphics card can sample directly, and add mipmaps, smaller copies for distant surfaces. Godot sums up why: VRAM compression reduces memory and bandwidth, and "These factors combined make VRAM compression a must-have for 3D games with high-resolution textures" (Godot documentation: Importing images).

As an artist you rarely pick the format by hand, but you choose the texture type, size and compression setting, and those decide most of a scene's texture memory. Hugh Chew's video Your Textures Are Killing Performance, Here's Why is a good artist-level overview: it separates the costs into VRAM, compression, GPU texture sampling and draw calls, then covers channel packing, streaming and mipmaps with a UE5 compression demo (YouTube: Your Textures Are Killing Performance, Here's…).

#How block compression works

All common GPU formats cut the image into small blocks (usually 4 × 4 pixels) and store each block in a fixed number of bytes. For the BCn family, each block stores two endpoint colours and a small index per pixel saying where it sits between them (Nathan Reed's coding blog: Understanding BCn Texture Compression Formats). The size is fixed, so the GPU can jump straight to any block, and the result is always "a 4:1 or 8:1 compression ratio" against uncompressed 8-bit RGBA (Nathan Reed's coding blog: Understanding BCn Texture Compression Formats).

The cost is lower quality. Each block can only hold a limited range of colours, so sharp colour changes and smooth gradients suffer. Reed shows why: BC1 stores its two endpoints "using RGB 5:6:5 format", and in his test it fails on a smooth gradient (Nathan Reed's coding blog: Understanding BCn Texture Compression Formats).

#The BCn family (desktop and console)

Format Bits per pixel Channels Typical use Unreal setting
BC1 (DXT1) 4 RGB, optional 1-bit alpha Base colour without alpha; cut-out masks Default, no alpha (Unreal Engine documentation)
BC3 (DXT5) 8 RGBA Colour with smooth alpha; colour plus a packed mask Default, with alpha (Unreal Engine documentation)
BC4 4 One channel Height, gloss, single masks Alpha (Unreal Engine documentation)
BC5 8 Two channels Tangent-space normal maps Normalmap (Unreal Engine documentation)
BC6H 8 RGB, half-float HDR HDR skies, light probes HDR Compressed (Unreal Engine documentation)
BC7 8 RGB or RGBA High-quality colour, with or without alpha BC7 (Unreal Engine documentation)

Bits per pixel and uses from Nathan Reed's overview (Nathan Reed's coding blog: Understanding BCn Texture Compression Formats).

Reed says BC2 is "never used nowadays" (Nathan Reed's coding blog: Understanding BCn Texture Compression Formats), and that BC7 handles gradients well: "BC7 also works extremely well on the gradient example, where BC1 failed miserably" (Nathan Reed's coding blog: Understanding BCn Texture Compression Formats). Unity's recommendation for modern desktop GPUs is DXT1 for RGB, BC7 for higher-quality RGBA (or DXT5 for faster compression), and BC6H for HDR (Unity Manual: Choose a GPU texture format by platform).

#Normal maps

Normal maps get their own format because colour compression distorts directions. BC5 stores only X and Y, each with its own endpoints, and the shader reconstructs Z (Nathan Reed's coding blog: Understanding BCn Texture Compression Formats). Unreal's Normalmap setting uses BC5 (Unreal Engine documentation: Texture Compression Settings). Godot imports normal maps as the equivalent RGTC format, noting that regular compression produces artefacts that "don't look that nice in normal maps" (Godot documentation: Importing images). Unity HDRP requires tangent-space normal maps to be BC7, BC5 or DXT5nm (High Definition Render Pipeline manual 17.0: Lit material Inspector reference). See normal map.

#Mobile: ASTC and ETC2

Phones and tablets use different formats.

Because the block size is chosen per texture, you can spend fewer bits on soft, distant textures and more on hero assets and UI.

#The sRGB flag

Compression format and colour space are separate choices. Colour textures are stored in sRGB and data textures in linear (see texture maps explained). glTF notes that "Graphics APIs usually support dedicated sRGB texture format enums that enable correct transfer function decoding and texture filtering" (Khronos Group: glTF 2.0 Specification). In practice:

#Mipmaps

A mipmap chain is a series of "progressively smaller and lower resolution versions of a single texture" (Unity Manual: Introduction to mipmaps). When a surface is far away, the GPU samples a smaller level. This "can speed up rendering operations and reduce rendering artifacts" such as shimmering (Unity Manual: Introduction to mipmaps). Each level halves the width and height, so Epic's tables show a 2048² texture with 12 mips down to 1 × 1 (Unreal Engine documentation: Texture Format Support and Settings in Unreal…).

The cost is memory: "Mipmaps increase the size of a texture by 33%, both on disk and in memory" (Unity Manual: Introduction to mipmaps). Mips are also the reason UV padding matters: small mips blur neighbouring islands together.

#Power-of-two sizes

Textures are traditionally 256, 512, 1024, 2048 or 4096 px on each side. Halving divides evenly all the way down to 1 × 1, and block compression needs sizes that are multiples of 4. benui's Unreal notes summarise it: "Power-of-two textures are supported by both compression and mipmap generation", and DXT5 "is only available for textures that are a multiple of 4" (Unreal Garden: UI Texture Size and Compression).

The rules have relaxed. benui notes that from Unreal 5.1 "Mip maps are now supported on non-power-of-two textures", but that Unreal has only supported streaming power-of-two textures since 4.16 (Unreal Garden: UI Texture Size and Compression). Unity can rescale a non-power-of-two image to the nearest power of two on import (Unity Manual: Default texture import settings reference). Rectangular power-of-two sizes such as 2048 × 1024 are fine; square is not required on desktop, though Unity notes that the old PVRTC mobile formats "require Textures to be square" (Unity Manual: Default texture import settings reference).

For 3D, keep to power-of-two sizes unless you have a reason not to.

#Worked example: texture memory

Texture memory is simple arithmetic: pixels × bytes per pixel × 4/3 for mips.

A large square labelled 2048 squared, 4 MiB, followed by progressively smaller orange squares labelled 1024 squared at 1 MiB, 512 squared at 256 KiB, and a tail of tiny squares labelled 256 squared to 1 squared, 85 KiB. Text reads: base level 2048 by 2048 by 1 byte equals 4 MiB; all smaller mips together about 1.33 MiB; total about 5.33 MiB, one third more.
A 2K BC7 texture: the base level is 4 MiB and the whole mip chain adds a third, for about 5.33 MiB.Diagram by the handbook author

#Texture streaming

Engines do not keep every mip of every texture in memory. Texture streaming loads and unloads mip levels as you move. Unreal's streamer calculates the resolution each texture needs from the viewpoint "to get a good texel per pixel ratio", checks whether "the streaming memory pool is big enough", and if not, drops quality "one mip at a time, until the planned solution gets under budget" (Unreal Engine documentation: Texture Streaming Overview). Unseen textures lose mips first (Unreal Engine documentation: Texture Streaming Overview).

When a scene is over budget, textures look blurry because their high mips never load. Unreal's texture-streaming view modes show where loaded mips are too low or too high, colouring objects red for "2X+ mips missing" and green for "2X+ extra mips" (Unreal Engine documentation: Building Texture Streaming Data in Unreal…). Unity has a comparable Mipmap Streaming option per texture (Unity Manual: Default texture import settings reference). See virtual texturing for the related page-based approach.

#Unreal texture groups and LOD bias

Unreal assigns each texture to a texture group (LOD group) such as World, WorldNormalMap, Character, Weapon, Vehicle, Effects, Skybox or UI (Unreal Engine documentation: Texture Format Support and Settings in Unreal…). Each group sets limits for every texture in it:

A texture's own LOD Bias is added to its group's: a group bias of 1 plus a texture bias of 1 gives 2 (Unreal Engine documentation: Texture Format Support and Settings in Unreal…). Groups are configured per platform in the project's DefaultDeviceProfiles.ini (Unreal Engine documentation: Texture Format Support and Settings in Unreal…). This lets one project keep 4K source textures and halve them automatically on a weaker platform, without re-exporting anything.

Unreal also limits textures to 14 mips by default, capping the largest rendered texture at 8192 (Unreal Engine documentation: Texture Format Support and Settings in Unreal…).

#Common mistakes

#In different tools

#Further reading and watching

Ties this page together with channel packing, mipmaps and draw calls; the UE5 compression demo starts at 25:27. Watch on YouTube

References

  1. Godot Engine contributors · Importing images (documentation source) · Godot documentation (GitHub) · docs · accessed 2026-10-21
  2. Hugh Chew · Your Textures Are Killing Performance, Here's Why · YouTube, 2026 · video · accessed 2026-10-21
  3. Nathan Reed · Understanding BCn Texture Compression Formats · Nathan Reed's coding blog, 2012 · article · accessed 2026-10-21
  4. Epic Games · Texture Compression Settings (Unreal Engine 4.27) · Unreal Engine documentation, 2021 · docs · accessed 2026-10-21
  5. Unity Technologies · Choose a GPU texture format by platform · Unity Manual (6000.2) · docs · accessed 2026-10-21
  6. Unity Technologies · Lit material Inspector reference (HDRP) · High Definition Render Pipeline manual 17.0 · docs · accessed 2026-10-21
  7. Khronos Group · glTF 2.0 Specification · Khronos Group (GitHub) · docs · accessed 2026-10-21
  8. Unity Technologies · Default texture import settings reference · Unity Manual (6000.2) · docs · accessed 2026-10-21
  9. Unity Technologies · Introduction to mipmaps · Unity Manual (6000.2) · docs · accessed 2026-10-21
  10. Epic Games · Texture Format Support and Settings in Unreal Engine · Unreal Engine documentation · docs · accessed 2026-10-21
  11. benui · UI Texture Size and Compression · Unreal Garden, 2022 · article · accessed 2026-10-21
  12. Epic Games · Texture Streaming Overview (Unreal Engine 4.27) · Unreal Engine documentation, 2021 · docs · accessed 2026-10-21
  13. Epic Games · Building Texture Streaming Data in Unreal Engine · Unreal Engine documentation · docs · accessed 2026-10-21

Last updated 2026-10-22