Instanced particle morph animation

const color = new THREE.Color();
    const sphereGeometry = new THREE.SphereGeometry(0.008, 16, 16);
    const particles = new THREE.InstancedMesh(
      sphereGeometry,
      new THREE.MeshStandardMaterial(),
      8000
    );
    particles.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
    const matrix = new THREE.Matrix4();
    const secondMatrix = new THREE.Matrix4();
    const group = new THREE.Group();
    scene.add(group);

    const globeRadius = 1.3;

    let sampler;
    let model;
    loader.load('/earth.glb', (gltf) => {
      model = gltf.scene;
      gltf.scene.traverse((obj) => {
        if (obj.isMesh) {
          obj.scale.set(0.4, 0.4, 0.4);
          sampler = new MeshSurfaceSampler(obj).build();
          for (let i = 0; i < 30000; i++) {
            const sample = new THREE.Vector3();
            sampler.sample(sample);
            sample.normalize();
            const phi = Math.atan2(sample.z, sample.x);
            const gradientPosition = (phi + Math.PI) / (2 * Math.PI);

            if (gradientPosition < 0.5) {
              color.lerpColors(new THREE.Color(0x006dff), new THREE.Color(0xfc0001), gradientPosition * 2);
            } else {
              color.lerpColors(new THREE.Color(0xfc0001), new THREE.Color(0xf2e300), (gradientPosition - 0.5) * 2);
            }

            sample.multiplyScalar(globeRadius);
            matrix.makeTranslation(sample.x, sample.y, sample.z);
            particles.setMatrixAt(i, matrix);
            particles.setColorAt(i, color);
          }

          group.add(particles)
          group.scale.set(0.36, 0.36, 0.36);
        }
      });
    });


    let secondModel;
    loader.load('/land.glb', (gltf) => {
      secondModel = gltf.scene;
      gltf.scene.traverse((obj) => {
        if (obj.isMesh) {
          obj.scale.set(0.4, 0.4, 0.4);
          sampler = new MeshSurfaceSampler(obj).build();
          for (let i = 0; i < 30000; i++) {
            const sample = new THREE.Vector3();
            sampler.sample(sample);

            secondMatrix.makeTranslation(sample.x, sample.y, sample.z);
            // particles.setMatrixAt(i, secondMatrix);
            particles.setColorAt(i, color);
          }
          group.scale.set(0.36, 0.36, 0.36);
        }
      });
    });

  // tl.to(?, {
  //   x:?,
  //   y:?,
  //   z:?,
  //   scrollTrigger: {
  //     trigger: "#page1",
  //     start: "bottom bottom",
  //     end: "bottom top",
  //     scrub: true,
  //     markers: true,
  //   }
  // })

i need to animate the particles like in this website WEBSITE
do you guys know how to achieve this morphing animation like in this site . i used gsap but its not working correctly. is shader is must wanted for these kind of morphing. or is there any other simple ways ?
if any one knows please help .

I would use points for such type of visuals. PointsMaterial needs minor changes to move particles from one formation to another.

But I don’t insist :slight_smile:

As you use instancing, you can interpolate position of an instance with JS :thinking:
Have a look at this example and its source code, to see how to change instance matrices: three.js examples

1 Like

i couldn’t find something helpfull. can you explain any solution please

Having two arrays with the same amount of positions for different formations, you can set position of each instance by interpolation between start and end points. For example, .lerpVectors()

dummy.positon.lerpVectors(start[i], end[i], a);
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
// where 'i' is the index of an instance

bro. i just switched to Points ,PointsMaterial .

const group = new THREE.Group();
    scene.add(group);
    const color = new THREE.Color();
    const particlesGeometry = new THREE.BufferGeometry();
    const Ppositions = [];
    const Pcolors = [];

    const globeRadius = 1.3;

    let sampler;
    let model;
    loader.load('/earth.glb', (gltf) => {
      model = gltf.scene;
      gltf.scene.traverse((obj) => {
        if (obj.isMesh) {
          obj.scale.set(0.4, 0.4, 0.4);
          sampler = new MeshSurfaceSampler(obj).build();
          for (let i = 0; i < 8000; i++) {
            const sample = new THREE.Vector3();
            sampler.sample(sample);
            sample.normalize();
            const phi = Math.atan2(sample.z, sample.x);
            const gradientPosition = (phi + Math.PI) / (2 * Math.PI);

            if (gradientPosition < 0.5) {
              color.lerpColors(new THREE.Color(0x006dff), new THREE.Color(0xfc0001), gradientPosition * 2);
            } else {
              color.lerpColors(new THREE.Color(0xfc0001), new THREE.Color(0xf2e300), (gradientPosition - 0.5) * 2);
            }

            sample.multiplyScalar(globeRadius);
            Ppositions.push(sample.x, sample.y, sample.z);
            Pcolors.push(color.r, color.g, color.b);
          }

          particlesGeometry.setAttribute('position', new THREE.Float32BufferAttribute(Ppositions, 3));
          particlesGeometry.setAttribute('color', new THREE.Float32BufferAttribute(Pcolors, 3));

          const material = new THREE.PointsMaterial({ size: 0.008, vertexColors: true, map: sprite });
          const particles = new THREE.Points(particlesGeometry, material);
          group.add(particles);
          group.scale.set(0.36, 0.36, 0.36);
        }
      });
    });





    let secondModel;
    loader.load('/land.glb', (gltf) => {
      secondModel = gltf.scene;
      gltf.scene.traverse((obj) => {
        if (obj.isMesh) {
          obj.scale.set(0.4, 0.4, 0.4);
          sampler = new MeshSurfaceSampler(obj).build();
          for (let i = 0; i < 8000; i++) {
            const sample = new THREE.Vector3();
            sampler.sample(sample);
            // Ppositions.push(sample.x, sample.y, sample.z);
            Pcolors.push(color.r, color.g, color.b);
          }

          particlesGeometry.setAttribute('position', new THREE.Float32BufferAttribute(Ppositions, 3));
          particlesGeometry.setAttribute('color', new THREE.Float32BufferAttribute(Pcolors, 3));
        }
      });
    });

can you say that minor changes that need for this particle animation .like this please

This is the example with morphing between models: https://codepen.io/prisoner849/pen/yLGGKqo

2 Likes

Hi @unni_krishnan , I have created an npm package to which can work for your use case. You can easily animate the particles from on formation to another using it. Though I have created it for React three fiber.
You can check it out!
r3f-points-fx - npm (npmjs.com)