How KHR_mesh_quantization Reduces glTF File Sizes

The KHR_mesh_quantization extension reduces glTF 3D model buffer sizes and GPU memory footprints by truncating high-precision vertex attributes into compact, lower-bit formats. Standard glTF files typically store geometry using 32-bit floating-point numbers for properties like positions, normals, and texture coordinates. By compressing these values into 8-bit or 16-bit integers and mapping them to a normalized range, the extension cuts vertex buffer sizes by up to 50% to 75% without requiring significant computational overhead or introducing noticeable visual degradation.

The Problem: 32-Bit Float Overhead

In default glTF 2.0 representations, each vertex attribute uses single-precision 32-bit floating-point numbers (FLOAT), which consume 4 bytes per component:

  • Positions (\(X, Y, Z\)): 12 bytes per vertex.
  • Normals (\(X, Y, Z\)): 12 bytes per vertex.
  • Tangents (\(X, Y, Z, W\)): 16 bytes per vertex.
  • Texture Coordinates (\(U, V\)): 8 bytes per vertex.

For complex meshes containing hundreds of thousands of vertices, storing raw floating-point buffers creates massive file payloads that slow down network transfers and saturate GPU memory bandwidth.

How Quantization Works

Quantization converts continuous 32-bit floating-point values into discrete integer values within a bounded domain. Instead of recording exact arbitrary floating-point numbers, KHR_mesh_quantization maps the bounding volume of the geometry to a discrete integer grid.

  1. Normalization and Scaling: The asset's bounding box is measured to determine the minimum and maximum boundaries of the mesh. Coordinates within this range are normalized, typically mapped to a \([0, 1]\) or \([-1, 1]\) interval.
  2. Bit-Depth Truncation: Continuous values are converted to fixed-size integers by multiplying the normalized value by the maximum integer representation and rounding:
    • Positions: Truncated from 32-bit floats to 16-bit signed or unsigned integers (SHORT or UNSIGNED_SHORT). This reduces position storage from 12 bytes to 6 bytes per vertex (a 50% reduction).
    • Normals and Tangents: Because normals represent unit vectors bounded strictly within \([-1, 1]\), they can be truncated to 8-bit signed integers (BYTE). This slashes normal attribute storage from 12 bytes down to 3 or 4 bytes per vertex (a 66% to 75% reduction).
    • Texture Coordinates: Mapped from 32-bit floats to 16-bit unsigned integers (UNSIGNED_SHORT), reducing UV data from 8 bytes to 4 bytes per vertex.

Hardware-Accelerated Dequantization

A major advantage of KHR_mesh_quantization is that it avoids costly CPU-side decompression before rendering. Modern graphics APIs (DirectX, Vulkan, Metal, and OpenGL/WebGL) natively support vertex buffer formats with lower-precision signed and unsigned normalized types (SNORM and UNORM).

When the GPU reads quantized attributes:

  • The hardware automatically unpacks normalized 8-bit or 16-bit integers back into floats on the fly during vertex attribute fetch.
  • For position data requiring non-uniform bounds, standard node transformations (scale and translation matrices) are applied in the vertex shader to scale the integer grid back to the original model dimensions.

Impact on Performance and Quality

By lowering the precision of vertex attributes:

  • Payload Size: Binary glTF (.glb) files shrink substantially, improving load times over web networks.
  • Cache Efficiency: Smaller vertex structures allow more vertices to fit into GPU L1/L2 caches, improving vertex shading throughput.
  • Visual Fidelity: 16-bit quantization divides an axis into 65,536 distinct steps. For most real-time 3D models, this resolution provides sub-millimeter precision, making the truncation invisible to the human eye under standard viewing conditions.