animationthree.jswebglbuffer-geometry

Three.js Buffer Geometry Animation


I have Three.js scene that basically spreads out a bunch of triangles over a given area.


        geometry = new THREE.BufferGeometry();
        geometry.dynamic = true;

        positions = new Float32Array(triangles * 3 * 3);
        const normals = new Float32Array(triangles * 3 * 3);
        const colors = new Float32Array(triangles * 3 * 3);

        const color = new THREE.Color();

        const n = 200,
          n2 = n / 2; // triangle's spread distance

        const d = 1000,
          d2 = d / 2; // individual triangle size

        const pA = new THREE.Vector3();
        const pB = new THREE.Vector3();
        const pC = new THREE.Vector3();

        const cb = new THREE.Vector3();
        const ab = new THREE.Vector3();

        for (let i = 0; i < positions.length; i += 9) {
          // position

          const x = Math.random() * n - n2;
          const y = Math.random() * n - n2;
          const z = Math.random() * n - n2;

          const ax = x + Math.random() * d - d2;
          const ay = y + Math.random() * d - d2;
          const az = z + Math.random() * d - d2;

          const bx = x + Math.random() * d - d2;
          const by = y + Math.random() * d - d2;
          const bz = z + Math.random() * d - d2;

          const cx = x + Math.random() * d - d2;
          const cy = y + Math.random() * d - d2;
          const cz = z + Math.random() * d - d2;

          positions[i] = ax;
          positions[i + 1] = ay;
          positions[i + 2] = az;

          positions[i + 3] = bx;
          positions[i + 4] = by;
          positions[i + 5] = bz;

          positions[i + 6] = cx;
          positions[i + 7] = cy;
          positions[i + 8] = cz;

          if (i === 0) console.log(positions);

          // flat face normals

          pA.set(ax, ay, az);
          pB.set(bx, by, bz);
          pC.set(cx, cy, cz);

          cb.subVectors(pC, pB);
          ab.subVectors(pA, pB);
          cb.cross(ab);

          cb.normalize();

          const nx = cb.x;
          const ny = cb.y;
          const nz = cb.z;

          normals[i] = nx;
          normals[i + 1] = ny;
          normals[i + 2] = nz;

          normals[i + 3] = nx;
          normals[i + 4] = ny;
          normals[i + 5] = nz;

          normals[i + 6] = nx;
          normals[i + 7] = ny;
          normals[i + 8] = nz;

          // colors

          const vx = x / n + 0.5;
          const vy = y / n + 0.5;
          const vz = z / n + 0.5;

          color.setRGB(vx, vy, vz);

          colors[i] = color.r;
          colors[i + 1] = color.g;
          colors[i + 2] = color.b;

          colors[i + 3] = color.r;
          colors[i + 4] = color.g;
          colors[i + 5] = color.b;

          colors[i + 6] = color.r;
          colors[i + 7] = color.g;
          colors[i + 8] = color.b;
        }

        geometry.setAttribute(
          "position",
          new THREE.BufferAttribute(positions, 3)
        );
        geometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3));
        geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));

        geometry.computeBoundingSphere();

        let material = new THREE.MeshPhongMaterial({
          color: 0xaaaaaa,
          specular: 0xffffff,
          shininess: 250,
          side: THREE.DoubleSide,
          vertexColors: true,
        });

        mesh = new THREE.Mesh(geometry, material);
        scene.add(mesh);

What I would like to do is have the triangles start close together, and expand in every direction randomly.

How can I create an animation loop that updates the triangles position?

I have been using this example code from three.js's website: https://github.com/mrdoob/three.js/blob/master/examples/webgl_interactive_buffergeometry.html

edit: I was able to make the triangles expand with this.mesh.scale.z += 0.005 but the triangles themselves grow as well. Is there a way to hold the triangle size the same but change the area the cover?


Solution

  • You could use morph targets.

    Made a codepen available here:
    https://codepen.io/cdeep/pen/WNENOmK

    The code is inspired from the three.js example:
    https://threejs.org/examples/?q=morph#webgl_morphtargets.

    While assigning the initial position for each vertex, also assign the final position of where the vertex must end up after expanding.

    In essence,

    const positions = new Float32Array( triangles * 3 * 3 );
    const morphedPositions = new Float32Array(triangles * 3 * 3);
    ...
    ...
    geometry.morphAttributes.position = [];
    geometry.morphAttributes.position[ 0 ] = new THREE.BufferAttribute( morphedPositions, 3);
    mesh.morphTargetInfluences[ 0 ] = morphValue;
    

    Animate the morphValue to influence how far the position attribute is closer to morphedPositions.