glTF Multiple Buffers in One JSON Descriptor
The glTF (GL Transmission Format) standard uses a flexible, modular
architecture that allows a single JSON descriptor file
(.gltf) to link to multiple separate binary buffer files
(.bin). Instead of embedding all binary payloads into a
monolithic container, the JSON file defines each external file as an
entry in a top-level array and maps sub-regions of these files to
geometric attributes, animations, and skinning data. This structural
separation enables efficient asset streaming, level-of-detail
management, and modular 3D pipeline workflows.
The Core Hierarchy: Buffers, BufferViews, and Accessors
glTF connects distinct binary files to 3D scene elements using a three-tier indexing system:
buffers: Declares the raw external binary files.bufferViews: Defines specific slices or windows of data within a given buffer.accessors: Interprets the raw bytes of abufferViewas structured data types (such asVEC3floating-point coordinates orSCALARindices).
Defining Multiple
Files in the buffers Array
At the root of the JSON file, the buffers property
contains an array of objects. Each object represents an individual
binary resource and requires two main properties:
uri: The relative file path, external URL, or base64 data URI pointing to the binary file.byteLength: The total size of that binary file in bytes.
{
"buffers": [
{
"uri": "geometry.bin",
"byteLength": 24000
},
{
"uri": "animations.bin",
"byteLength": 8192
}
]
}In this setup, indices reference each buffer based on its position in
the array (geometry.bin is index 0, and
animations.bin is index 1).
Slicing Files with
bufferViews
The bufferViews array segments the data inside the
defined buffers. Each bufferView references a specific
buffer by its array index using the buffer key:
{
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 12000,
"target": 34962
},
{
"buffer": 0,
"byteOffset": 12000,
"byteLength": 12000,
"target": 34962
},
{
"buffer": 1,
"byteOffset": 0,
"byteLength": 8192
}
]
}buffer: The index of the target buffer in thebuffersarray.byteOffset: The starting position (in bytes) within that specific file (defaults to0).byteLength: The length of the slice (in bytes).target: An optional OpenGL buffer target (e.g.,34962forARRAY_BUFFER,34963forELEMENT_ARRAY_BUFFER).
Because bufferViews explicitly declare which buffer
index they target, bufferView 0 and
1 read exclusively from geometry.bin, while
bufferView 2 reads from
animations.bin.
Reading Data Through
accessors
Higher-level glTF components—such as mesh primitives or animation
channels—do not read buffers directly. Instead, they reference
accessors, which point to the relevant
bufferView.
{
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5126,
"count": 1000,
"type": "VEC3",
"max": [1.0, 1.0, 1.0],
"min": [-1.0, -1.0, -1.0]
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 64,
"type": "SCALAR"
}
]
}- The first accessor reads vertex positions from
bufferView0(located ingeometry.bin). - The second accessor reads animation keyframe timestamps from
bufferView2(located inanimations.bin).
Why Use Multiple Buffers?
Structuring a glTF asset with multiple binary buffers offers several technical benefits:
- Progressive Loading: Geometry can be loaded and rendered immediately, while animation or morph target buffers are fetched asynchronously in the background.
- Asset Sharing and Reuse: Multiple distinct models can share the same animation or skinning buffer file, reducing overall download sizes in web and game engines.
- Independent Updates: Static geometry and dynamic physics or animation sets can be updated or versioned independently without repacking the entire asset.