Particle Systems

Lesson 7

Points + BufferGeometry = thousands of particles with minimal overhead. Store positions in a Float32Array and update them on the CPU each frame.

Creating 5k Particles

const count = 5000;
const positions = new Float32Array(count * 3);

for (let i = 0; i < count; i++) {
  positions[i * 3]     = (Math.random() - 0.5) * 10;
  positions[i * 3 + 1] = (Math.random() - 0.5) * 10;
  positions[i * 3 + 2] = (Math.random() - 0.5) * 10;
}

const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));

const material = new THREE.PointsMaterial({ size: 0.02, color: 0xffffff });
const particles = new THREE.Points(geometry, material);
scene.add(particles);

Updating Positions Each Frame

const posAttr = geometry.attributes.position;

// In animate():
const t = clock.getElapsedTime();
for (let i = 0; i < count; i++) {
  const ix = i * 3;
  posAttr.array[ix + 1] += Math.sin(t + posAttr.array[ix] * 0.5) * 0.001;
}
posAttr.needsUpdate = true; // required after CPU mutation

What to Experiment With

  • Scale PointsMaterial.size by devicePixelRatio for consistent look
  • Use a circular texture (white circle on transparent) for soft particles
  • Add a slow particles.rotation.y += 0.0003 for global drift