Animate Particles

I am trying to figure out how to move particles from one shape to another. Using a shader is probably the most efficient way but I have a very base level knowledge of how to make them. This website is a good example of what I’m looking to do with the particles.
https://dala.craftedbygc.com/

Right now I’m mapping a couple objects and placing a particle at each vertex and doing the same with a sphere geometry. I’m looking to start with the egg particles and explode them out into the sphere and then pull them back into the shape of the unicorn.

const particleMaterial = new THREE.PointsMaterial({
  color: 0xffffff, // Particle color
  size: 1, // Particle size
  opacity: 0.8,
  depthWrite: false,
  blending: THREE.AdditiveBlending,
});

async function loadUnicornPoints() {
  return new Promise((resolve, reject) => {
    loader.load("Unicorn.glb", function (object) {
      const vertices = [];

      object.scene.traverse(function (child) {
        if (child.isMesh) {
          vertices.push(...child.geometry.attributes.position.array);
        }
      });
      const p_geom = new THREE.BufferGeometry();
      p_geom.setAttribute(
        "position",
        new THREE.Float32BufferAttribute(vertices, 3)
      );

      const unicornPoints = new THREE.Points(p_geom, particleMaterial);
      unicornPoints.rotateX(Math.PI / 2);
      unicornPoints.scale.set(120, 120, 120);

      resolve(unicornPoints); // Resolve the promise with unicornPoints
    });
  });
}

async function loadEggPoints() {
  return new Promise((resolve, reject) => {
    loader.load("Egg.glb", function (object) {
      const vertices = [];

      object.scene.traverse(function (child) {
        if (child.isMesh) {
          vertices.push(...child.geometry.attributes.position.array);
        }
      });

      const p_geom = new THREE.BufferGeometry();
      p_geom.setAttribute(
        "position",
        new THREE.Float32BufferAttribute(vertices, 3)
      );

      const unicornPoints = new THREE.Points(p_geom, particleMaterial);
      unicornPoints.rotateX(Math.PI / 2);
      unicornPoints.scale.set(20, 20, 20);

      resolve(unicornPoints);
    });
  });
}
const eggPoints = await loadEggPoints();
scene.add(eggPoints);
const unicornPoints = await loadUnicornPoints();
scene.add(unicornPoints);
const particlesCount = eggPoints.geometry.attributes.position.count;
const positions = new Float32Array(particlesCount * 3);

const sphereRadius = 100;

for (let i = 0; i < particlesCount; i++) {
  const phi = Math.acos(-1 + (2 * i) / particlesCount);
  const theta = Math.sqrt(particlesCount * Math.PI) * phi;

  // Calculate the coordinates with the scaled radius
  const x = sphereRadius * Math.cos(theta) * Math.sin(phi);
  const y = sphereRadius * Math.sin(theta) * Math.sin(phi);
  const z = sphereRadius * Math.cos(phi);

  positions[i * 3] = x;
  positions[i * 3 + 1] = y;
  positions[i * 3 + 2] = z;
}

const particleGeometry = new THREE.BufferGeometry();
particleGeometry.setAttribute(
  "position",
  new THREE.BufferAttribute(positions, 3)
);

const particleSystem = new THREE.Points(particleGeometry, particleMaterial);

scene.add(particleSystem);

I learn best by taking code that is close enough to what I need and figuring out how to make it work for my project. If anyone could get me started or point me to an example that is fairly similar, that would be much appreciated.

Also, I think a custom shader is the way to go but I would still be interested in how to do this using something like gsap

I’d suggest that you start with the simplest approach – by having two shapes with the same number of vertices and transition your points from the first shape to the second.

For example, if A and B are the shapes, and p is the set of particles then:

p[ i ] = lerp( A[ i ], B[ i ], k )

will set i-th particle between the i-th vertex of A and i-th vertex of B. When you change k from 0 to 1, the particles will travel from shape A to shape B.

Here is a demo for transition between rounded plate and a sphere:

https://codepen.io/boytchev/full/rNoGwqo

image

I hope this could be enough for you to get started. Later on, when you need more performance, you may switch to instances.

5 Likes

The using of InstancedMesh:

6 Likes

Both of these are very helpful. Thanks very much