How to Update BufferGeometry Vertices in Three.js

Updating the vertex positions of an active BufferGeometry in Three.js is a crucial technique for creating dynamic animations, terrain deformations, or interactive 3D effects. This article provides a straightforward guide on how to access a geometry’s position attribute, modify its underlying coordinate data, and signal Three.js to successfully render these changes on the screen.

Accessing and Modifying Vertex Positions

To update the vertices of a BufferGeometry, you must directly access its position attribute. This attribute contains a typed array storing the X, Y, and Z coordinates of every vertex in the 3D model.

Here is the step-by-step process to update these coordinates:

  1. Access the position attribute: Retrieve the position attribute from the geometry.
  2. Modify the data: Loop through the vertices and change their coordinates.
  3. Set the update flag: Set the attribute’s needsUpdate property to true. This tells Three.js to upload the new vertex data to the GPU.

Code Example

The following code demonstrates how to modify the Y-coordinates of a geometry over time, creating a simple wave effect:

// 1. Get the position attribute
const positionAttribute = geometry.attributes.position;

// Use a loop to modify each vertex
for (let i = 0; i < positionAttribute.count; i++) {
    // Read current coordinate values
    const x = positionAttribute.getX(i);
    const z = positionAttribute.getZ(i);

    // Calculate a new Y position (e.g., using a sine wave)
    const newY = Math.sin(x + time) * Math.cos(z + time);

    // Write the updated Y coordinate back to the attribute
    positionAttribute.setY(i, newY);
}

// 2. Signal Three.js that the vertex data has changed
positionAttribute.needsUpdate = true;

Performance Optimization with Usage Hints

If you plan to update your vertex positions frequently (for example, on every frame in the animation loop), you should inform the GPU. This allows the graphics card to allocate the memory more efficiently for frequent writes.

You can do this by setting the usage pattern of the BufferAttribute to DynamicDrawUsage right after creating your geometry:

// Set the usage to dynamic for frequent updates
geometry.attributes.position.setUsage(THREE.DynamicDrawUsage);

By combining DynamicDrawUsage with needsUpdate = true, you can achieve smooth, real-time vertex animations in Three.js without sacrificing web browser performance.