glTF Interleaved vs Non-Interleaved Vertex Buffers
The glTF 2.0 specification natively supports both interleaved and
non-interleaved vertex buffer layouts through its hierarchical data
storage architecture consisting of buffers, buffer views, and accessors.
In glTF, the choice between structuring vertex attributes separately or
packaging them into a single interleaved array is managed by setting the
byteStride property in a bufferView and
adjusting the byteOffset inside corresponding
accessors. This design allows graphics pipelines to
optimize for cache locality, memory bandwidth, or dynamic data updates
without altering the underlying mesh definition.
The glTF Data Architecture
To understand how glTF formats vertex layouts, it is necessary to examine three core entities in the glTF JSON structure:
buffers: Raw binary blobs containing geometry data.bufferViews: Slices of a buffer defining a byte offset, a byte length, and an optionalbyteStride.accessors: Definitions that describe how to read typed data (e.g.,VEC3ofFLOAT) from abufferView, defining component types, counts, and sub-offsets (byteOffset).
The handling of interleaved versus non-interleaved configurations
depends directly on how bufferViews and
accessors interact.
Non-Interleaved (Separate) Vertex Buffers
In a non-interleaved (or planar) layout, each vertex attribute—such as position, normal, and texture coordinate—is stored in its own distinct, contiguous memory block.
- Structure: Vertex positions are grouped together (P0, P1, P2...), followed by all normals (N0, N1, N2...), and so forth.
- glTF Implementation: Each attribute typically
points to its own distinct
bufferView(or non-overlapping regions within the samebufferView). Because the data is tightly packed, thebufferVieweither omits thebyteStrideproperty or sets it to the size of a single element (e.g., 12 bytes for aVEC3of 32-bit floats). Eachaccessorsimply references the start of its respective attribute array.
Use Case: Non-interleaved layouts are ideal when certain vertex attributes are updated frequently (such as software skinning or morph targets affecting only positions) or when rendering passes only require a subset of attributes (such as a depth-only shadow pass that only needs positions).
Interleaved Vertex Buffers
In an interleaved layout, all attributes for a single vertex are stored together sequentially in memory (P0, N0, UV0, P1, N1, UV1...).
- Structure: A single array of structures where each element represents the complete set of attributes for a single vertex.
- glTF Implementation:
- A single
bufferViewencompasses the entire interleaved array. - The
bufferViewdefines abyteStrideproperty, which represents the total size in bytes of one complete vertex (e.g., 12 bytes for position + 12 bytes for normal + 8 bytes for UV = 32-byte stride). According to the glTF specification,byteStridemust be a multiple of 4 and between 4 and 252 bytes. - Multiple
accessorsreference this identicalbufferView. Each accessor uses its ownbyteOffsetto point to the start of its specific attribute within the first vertex (e.g., position at offset 0, normal at offset 12, UV at offset 24).
- A single
Use Case: Interleaved layouts maximize GPU cache efficiency during standard rendering passes where all vertex attributes are consumed simultaneously by the vertex shader.
Key Rules and Restrictions in the Specification
- When
byteStrideis defined on abufferView, it applies to allaccessorsreferencing that view. - An
accessor.byteOffsetwithin an interleavedbufferViewmust be aligned to the component type size (e.g., an attribute usingFLOATcomponents must have an offset that is a multiple of 4). - glTF allows a hybrid approach within the same model: static
attributes (like normals and UVs) can be interleaved in one
bufferView, while dynamically modified attributes (like positions) remain non-interleaved in another.