Manipulate vertices on the go in AFrame?

262 Views Asked by At

I have a custom plane:

JS:

AFRAME.registerGeometry('example', {
      schema: {
        vertices: {
          default: ['-10 10 0', '-10 -10 0', '10 -10 0', '10 -10 0'],
        }
      },

      init: function (data) {
        var geometry = new THREE.Geometry();
        geometry.vertices = data.vertices.map(function (vertex) {
            var points = vertex.split(' ').map(function(x){return parseInt(x);});
            return new THREE.Vector3(points[0], points[1], points[2]);
        });
        geometry.computeBoundingBox();
        geometry.faces.push(new THREE.Face3(0, 1, 2));
        geometry.faces.push(new THREE.Face3(0, 2, 3));
        geometry.mergeVertices();
        geometry.computeFaceNormals();
        geometry.computeVertexNormals();
        this.geometry = geometry;
      }
    });

Html:

<a-entity id="myPlane" geometry="primitive: example; vertices: 1 1 -3, 3 1 -3, 2 2 -3, 1 2 -3"></a-entity>

How could I now manipulate the vertices position in an animation loop?

Lets say the first point:

geometry.vertices[0] 

I know I can access the mesh with following:

document.getElementById("myPlane").object3D;

and change its position for example:

document.getElementById("myPlane").object3D.position.set(1,0,0)

but there is no vertices on the geometry of the plane mesh:

document.getElementById("plane").object3D.children[0]

how to manipulate the vertices of that geometry?

EDIT:

I found out you can update the position of the vertices like this:

document.getElementById("myPlane").object3D.children[0].geometry.attributes.position.array[0] = 20;

document.getElementById("myPlane").object3D.children[0].geometry.attributes.position.needsUpdate = true;

would like to do the whole manipulation in the tick() function, because what I really want is to connect two objects with a line.

Now the vertices of the plane looks like this:

Float32Array(18) [-0, 0, -3, 0, 1, -3, 2, 2, -3, 1, 1, -3, 2, 2, -3, 1, 2, -3]

since the plane has 4 points I expected to have 4*3 = 12 elements, but we got here 18 elements. What is the rest beside xyz?

1

There are 1 best solutions below

0
On

The vertices are available as an attribute of the objects geometry:

// mesh
const mesh = element.getObject3D("mesh");
// "vertices"
const vertices = mesh.geometry.attributes.position.array;

And you can simply change anything you want, and confirm the updates with:

mesh.geometry.attributes.position.needsUpdate = true;

The big complication comes with the difference between indexed and non-indexed geometry. In a nutshell:

  • non-indexed geometry contains all the vertices for any triangle in the mesh. A plane contains two triangles, therefore there are 2 triangles * 3 vertices * 3 coords = 18 entries. This can be illustrated in this example, where I manipulate a vertex, but only one triangle is affected:

<script src="https://aframe.io/releases/1.0.0/aframe.min.js"></script>
<script>
  AFRAME.registerComponent("foo", {
    init: function() {
      this.el.addEventListener("loaded", e => {
        const mesh = this.el.getObject3D("mesh");
        this.positionAttr = mesh.geometry.attributes.position;
      })
    },
    tick: function(time) {
      // manipulate "Y" of the third vertex
      let offset = 0.25 * Math.sin(time * 0.001);
      this.positionAttr.array[2 * 3 + 1] = 0.5 + offset;
      this.positionAttr.needsUpdate = true;
    }
  })
</script>

<a-scene>
  <a-plane position="0 1.5 -2" wireframe="true" material="color: blue" foo></a-plane>
</a-scene>

  • indexed geometry doesn't like repeating the same vertices twice, so it stores unique vertices, and provides "indexes" referencing any stored vertex. Now manipulating a vertex looks quite different:

<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script>
  AFRAME.registerComponent("foo", {
    init: function() {
      this.el.addEventListener("loaded", e => {
        const mesh = this.el.getObject3D("mesh");
        this.positionAttr = mesh.geometry.attributes.position;
      })
    },
    tick: function(time) {
      let offset = 0.25 * Math.sin(time * 0.001);
      this.positionAttr.array[4] = 0.5 + offset;
      this.positionAttr.needsUpdate = true;
    }
  })
</script>

<a-scene>
  <a-plane position="0 1.5 -2" wireframe="true" material="color: blue" foo></a-plane>
</a-scene>

The code looks identical, but a-frame versions are different - you should get the same results when changing geometries (geometry.toNonIndexed())