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;