Three.js Particles: BufferGeometry and PointsMaterial

Rendering high-performance particle systems in Three.js is achieved by combining BufferGeometry and PointsMaterial within a Points mesh. This article provides a step-by-step guide on how to define particle positions, configure their visual appearance, and render them efficiently in a 3D scene.

Step 1: Define the Particle Geometry

To render particles efficiently, use THREE.BufferGeometry. This class stores vertex data in GPU-friendly arrays, which is crucial for handling thousands of individual particles without performance lag.

First, initialize a BufferGeometry object and populate a Float32Array with the 3D coordinates (X, Y, Z) for each particle.

import * as THREE from 'three';

// Define the number of particles
const particleCount = 5000;

// Create a flat array to hold coordinates (3 values per particle: x, y, z)
const positions = new Float32Array(particleCount * 3);

// Fill the array with random positions
for (let i = 0; i < particleCount * 3; i++) {
    positions[i] = (Math.random() - 0.5) * 10; // Values between -5 and 5
}

// Create geometry and assign the position attribute
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));

Step 2: Configure the PointsMaterial

The THREE.PointsMaterial class defines the appearance of the particles. You can customize properties such as color, size, and whether the particles should scale based on their distance from the camera.

const material = new THREE.PointsMaterial({
    color: 0x00ff88,             // Base color of the particles
    size: 0.05,                  // Size of each particle
    sizeAttenuation: true,       // Nearer particles appear larger
    transparent: true,           // Enables transparency support
    opacity: 0.8                 // Overall opacity of the system
});

Note: For more complex visual effects, you can assign a custom texture to the map property of the material.

Step 3: Instantiate the Points Mesh

In Three.js, you do not use the standard THREE.Mesh to render particles. Instead, use THREE.Points, which is specifically optimized to render vertices as individual points. Pass the configured geometry and material to this constructor, then add it to your scene.

// Combine geometry and material into a Points system
const particleSystem = new THREE.Points(geometry, material);

// Add the system to your Three.js scene
scene.add(particleSystem);

Step 4: Animating the Particles (Optional)

To bring your particle system to life, you can rotate the entire system inside your animation loop, or dynamically update individual particle coordinates.

To rotate the entire system:

function animate() {
    requestAnimationFrame(animate);

    // Rotate the particle system on its axes
    particleSystem.rotation.y += 0.002;
    particleSystem.rotation.x += 0.001;

    renderer.render(scene, camera);
}
animate();