Custom Vertices and Faces in Three.js BufferGeometry
This article provides a practical guide on how to create custom 3D
shapes in Three.js using the BufferGeometry class. You will
learn how to define custom vertex coordinates, group them into
triangular faces using indices, and apply these attributes to render a
custom mesh in your 3D scene.
To define custom geometry in modern Three.js, you must use
BufferGeometry. Unlike the deprecated Geometry
class, BufferGeometry stores data in raw binary arrays
called BufferAttributes, which are highly optimized for the
GPU.
Step 1: Define the Vertices
Vertices are points in 3D space defined by X, Y, and Z coordinates.
To define vertices, create a flat Float32Array where every
three consecutive numbers represent the X, Y, and Z coordinates of a
single point.
import * as THREE from 'three';
const geometry = new THREE.BufferGeometry();
// Define 4 vertices for a flat square (quad)
const vertices = new Float32Array([
-1.0, -1.0, 0.0, // Vertex 0 (bottom-left)
1.0, -1.0, 0.0, // Vertex 1 (bottom-right)
1.0, 1.0, 0.0, // Vertex 2 (top-right)
-1.0, 1.0, 0.0 // Vertex 3 (top-left)
]);
// Add the vertices to the geometry as the 'position' attribute
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));The second argument of THREE.BufferAttribute (in this
case, 3) specifies how many values in the array represent a
single vertex.
Step 2: Define the Faces (Indices)
Faces in Three.js are always built using triangles. Instead of duplicating vertex coordinates for shared edges, you define face “indices.” An index array references the vertex positions by their order of definition (starting at index 0).
To draw a quad, you need two triangles: one using vertices 0, 1, and 2, and another using vertices 0, 2, and 3.
// Define the index array to connect vertices into triangles
const indices = new Uint16Array([
0, 1, 2, // First triangle
0, 2, 3 // Second triangle
]);
// Set the index of the geometry
geometry.setIndex(new THREE.BufferAttribute(indices, 1));Using setIndex tells Three.js how to connect the
vertices to form the geometric faces.
Step 3: Compute Normals for Lighting
If your custom mesh interacts with light sources, you need to define face normals. Normals tell the renderer which direction a face is pointing. Instead of calculating these manually, Three.js can compute them automatically:
geometry.computeVertexNormals();Step 4: Create and Render the Mesh
With the geometry defined, you can now combine it with a material and add it to your scene.
const material = new THREE.MeshStandardMaterial({ color: 0xff0000, side: THREE.DoubleSide });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);By managing vertex positions and face index arrays directly, you can programmatically construct any 2D or 3D shape within Three.js.