Max Vertex Count in glTF Using 16-Bit Indices
In glTF, the maximum vertex count achievable in a single mesh primitive using 16-bit indices is exactly 65,536 vertices. This limit is dictated by the maximum value of an unsigned 16-bit integer, which can address index values ranging from 0 to 65,535. This article breaks down how glTF index accessors operate, why this limit exists, and how developers can accommodate larger models.
The 16-Bit Index Boundary
When a glTF mesh primitive defines an indexed geometry, it references
an accessor to retrieve index values. For 16-bit indexing, glTF uses the
UNSIGNED_SHORT component type (represented by the
identifier 5123).
An unsigned 16-bit integer has a numerical range of:
- Minimum index value: 0
- Maximum index value: 65,535 (\(2^{16} - 1\))
Because array indexing is zero-based, indices 0 through 65,535 provide a total of 65,536 unique addressable slots. Therefore, an individual glTF primitive relying on 16-bit indices cannot reference more than 65,536 distinct vertex attribute entries.
Why 16-Bit Indices Are Used
Using 16-bit indices is a common optimization in 3D graphics and glTF delivery. Compared to 32-bit indices, 16-bit indices:
- Halve index buffer size: An index buffer with 16-bit elements consumes 2 bytes per index instead of 4 bytes, reducing transmission payload and GPU memory footprint.
- Broaden compatibility: Many mobile graphics pipelines and older WebGL implementations process 16-bit index buffers natively with maximum performance and minimal overhead.
Overcoming the 65,536 Vertex Limit
If a 3D asset exceeds the 65,536 vertex threshold, two primary solutions exist within the glTF 2.0 specification:
- Switch to 32-Bit Indices: Change the accessor's
componentTypetoUNSIGNED_INT(identifier5125). This expands the addressable vertex limit to 4,294,967,296 (\(2^{32}\)) vertices per primitive at the cost of doubled index buffer memory. - Split into Multiple Primitives: Divide the geometry across multiple primitives within the same mesh or across multiple nodes. Each primitive can then maintain its own independent 16-bit index buffer, retaining memory savings without exceeding the index capacity.