C. Windolf C. Windolf - 7 months ago 7
Javascript Question

How can I add faces to an indexed THREE.BufferGeometry?

Say that I had generated a

THREE.BufferGeometry
from a
THREE.Geometry
named
oldGeom
like so:

// using WebGLRenderer
var geometry = new THREE.BufferGeometry();
var indices = new Uint16Array(oldGeom.vertices.length);
var vertices = new Float32Array(oldGeom.vertices.length * 3);
for (var i = 0; i < oldGeom.vertices.length; i++) {
indices[i] = i;
vertices[i * 3 + 0] = oldGeom.vertices[i].x;
vertices[i * 3 + 1] = oldGeom.vertices[i].y;
vertices[i * 3 + 2] = oldGeom.vertices[i].z;
}
geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.setIndex(new THREE.BufferAttribute(indices, 1));


Hopefully I have the indexing right. At this point, how could I add a face using the indices? I'm planning to loop through the faces of
oldGeom
to add them all here, but I can't find any documentation on this. Thanks!

Similar to this question, but with an indexed geometry.

JCD JCD
Answer

From the documentation for BufferGeometry:

index (itemSize: 3)

Allows for vertices to be re-used across multiple triangles; this is called using "indexed triangles," and works much the same as it does in Geometry: each triangle is associated with the index of three vertices. This attribute therefore stores the index of each vertex for each triangular face. If this attribute is not set, the renderer assumes that each three contiguous positions represent a single triangle.

The way "indexed triangles" work is that "position" is an array of numbers, with every consecutive set of 3 numbers representing one vertex (x, y, z). "Index" is an array of numbers, where every consecutive set of 3 numbers represents one face, by referring to the indices of vertices in the "position" array.

You might have an array of vertices like this:

var vertices = [0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0];

You can think of this array as sets of XYZ coordinates like this:

var vertices = [
    0, 0, 0, // vertex index 0
    1, 0, 0, // vertex index 1
    1, 1, 0, // vertex index 2
    0, 1, 0  // vertex index 3
];

Now if you have an index array like this:

var indices = [0, 1, 2, 1, 2, 3];

It represents two triangles:

var indices = [
    0, 1, 2, // face with vertices at indices 0, 1, 2
    1, 2, 3  // face with vertices at indices 1, 2, 3
];

So triangle #1 has vertices at XYZ (0, 0, 0), (1, 0, 0), (1, 1, 0) while triangle #2 has vertices at XYZ (1, 0, 0), (1, 1, 0), (0, 1, 0).

On the other hand you can define vertices without using an index. The power of indexing is that it lets you reuse vertices defined in the array instead of listing them redundantly every time they appear in a triangle. If you have a single array, vertices, then quite simply, every set of 9 numbers in the array is one triangle (three sets of consecutive vertices, each with three consecutive XYZ values).

Going back to your original question, if you want to add triangles to your BufferedGeometry, I see two basic options:

  1. Add the triangles to the original oldGeom object, and then convert it. It's a lot easier to add triangles to Geometry than it is BufferGeometry. Remember that the whole point of BufferGeometry is that it's not supposed to change! You would also be able to take advantage of .fromGeometry() because the new faces are already defined in oldGeom.
  2. Make an indices array that's larger than necessary for the original indices and manually define triangles there. If you're defining new vertices that don't exist in the vertices array then you'd have to add them in there too. What a pain in the butt.