How to Use Three.js InterleavedBuffer
This article explains how to define and use custom interleaved data
buffers in Three.js using InterleavedBuffer and
InterleavedBufferAttribute. You will learn how to combine
multiple vertex attributes—such as positions, colors, and UV
coordinates—into a single, contiguous array buffer to optimize GPU
memory access and improve rendering performance.
Understanding Interleaved Buffers
By default, Three.js geometries often use separate arrays (buffers) for different vertex attributes, such as one array for positions, one for normals, and another for UVs. This is known as a non-interleaved or “array of structures” approach.
Interleaving merges these attributes into a single array. Instead of
storing all positions followed by all UVs, you store them sequentially
for each vertex:
[position_x, position_y, position_z, uv_u, uv_v, ...].
This structure improves GPU cache locality because all data required to process a single vertex is located next to each other in memory.
Step 1: Create the Raw Typed Array
To set up an interleaved buffer, first define a single typed array
(usually a Float32Array) containing all your vertex data.
You must determine a consistent “stride,” which is the total number of
elements allocated for each vertex.
In this example, each vertex has a 3-element position
(x, y, z) and a 2-element UV coordinate
(u, v). The stride is 5.
// A single triangle with interleaved Position (3 floats) and UV (2 floats)
const vertexData = new Float32Array([
// x, y, z, u, v
0.0, 1.0, 0.0, 0.5, 1.0, // Vertex 1
-1.0, -1.0, 0.0, 0.0, 0.0, // Vertex 2
1.0, -1.0, 0.0, 1.0, 0.0 // Vertex 3
]);Step 2: Instantiate the InterleavedBuffer
Next, pass your typed array and the calculated stride to the
THREE.InterleavedBuffer constructor. The stride parameter
tells Three.js how many elements make up a single complete vertex
block.
import * as THREE from 'three';
const stride = 5; // 3 positions + 2 UVs
const interleavedBuffer = new THREE.InterleavedBuffer(vertexData, stride);Step 3: Define InterleavedBufferAttributes
To let your shader know where each attribute begins and how many
elements it uses, create instances of
THREE.InterleavedBufferAttribute.
The constructor accepts three parameters: 1.
InterleavedBuffer: The shared buffer
created in Step 2. 2. itemSize: How many
elements belong to this attribute (e.g., 3 for positions, 2 for UVs). 3.
offset: The starting index of this
attribute within the stride.
// Positions start at index 0 and have 3 elements (x, y, z)
const positionAttribute = new THREE.InterleavedBufferAttribute(interleavedBuffer, 3, 0);
// UVs start at index 3 (after x, y, z) and have 2 elements (u, v)
const uvAttribute = new THREE.InterleavedBufferAttribute(interleavedBuffer, 2, 3);Step 4: Assign Attributes to BufferGeometry
Finally, instantiate a standard THREE.BufferGeometry and
assign your custom interleaved attributes using
.setAttribute().
const geometry = new THREE.BufferGeometry();
// Assign the custom attributes
geometry.setAttribute('position', positionAttribute);
geometry.setAttribute('uv', uvAttribute);
// Create a mesh using the geometry
const material = new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.DoubleSide });
const mesh = new THREE.Mesh(geometry, material);Once assigned, Three.js automatically manages uploading the single interleaved buffer to the GPU, streamlining memory bandwidth during rendering.