Change CylinderGeometry Dynamically in Three.js

This article explains how to dynamically update the radius and height segments of a CylinderGeometry in Three.js after it has been rendered. Because Three.js geometries are uploaded to the GPU as static buffers, changing structural properties like segment counts requires recreating the geometry and reassigning it to the mesh. Below, you will find the standard, memory-safe approach to achieving this effect in real-time.

Why You Must Recreate the Geometry

In Three.js, properties like radialSegments and heightSegments define the number of vertices and faces used to build the cylinder’s shape. Once a geometry is rendered, its vertex buffer size is fixed on the GPU. You cannot simply modify geometry.parameters.radialSegments and expect the model to update.

To change the segment count dynamically, you must generate a new geometry with the updated parameters, assign it to the existing mesh, and dispose of the old geometry to prevent memory leaks.

Implementation Code

Here is the standard function to dynamically update a cylinder’s dimensions and segment counts:

function updateCylinderGeometry(mesh, newParams) {
    // 1. Dispose of the old geometry to free up GPU memory
    mesh.geometry.dispose();

    // 2. Create a new geometry with the updated parameters
    const newGeometry = new THREE.CylinderGeometry(
        newParams.radiusTop !== undefined ? newParams.radiusTop : mesh.geometry.parameters.radiusTop,
        newParams.radiusBottom !== undefined ? newParams.radiusBottom : mesh.geometry.parameters.radiusBottom,
        newParams.height !== undefined ? newParams.height : mesh.geometry.parameters.height,
        newParams.radialSegments !== undefined ? newParams.radialSegments : mesh.geometry.parameters.radialSegments,
        newParams.heightSegments !== undefined ? newParams.heightSegments : mesh.geometry.parameters.heightSegments,
        newParams.openEnded !== undefined ? newParams.openEnded : mesh.geometry.parameters.openEnded,
        newParams.thetaStart !== undefined ? newParams.thetaStart : mesh.geometry.parameters.thetaStart,
        newParams.thetaLength !== undefined ? newParams.thetaLength : mesh.geometry.parameters.thetaLength
    );

    // 3. Assign the new geometry to the mesh
    mesh.geometry = newGeometry;
}

How to Use the Function

To use this function in your application (for example, inside a UI event listener or an animation loop), pass your cylinder mesh and an object containing the new segment or radius values:

// Example: Dynamically increase the radial segments and height
updateCylinderGeometry(myCylinderMesh, {
    radiusTop: 3,
    radiusBottom: 3,
    radialSegments: 32, // Smooths the cylinder
    heightSegments: 8   // Adds more vertical loops
});

Alternative: Scaling for Radius and Height Only

If you only need to change the radius or height of the cylinder without changing the segment detail, you do not need to recreate the geometry. Instead, scale the mesh directly using the scale property, which is computationally cheaper and occurs instantly on the GPU:

// Double the radius (X and Z axes)
myCylinderMesh.scale.x = 2;
myCylinderMesh.scale.z = 2;

// Double the height (Y axis)
myCylinderMesh.scale.y = 2;