# Faces on BufferGeometry

I’m trying to draw the just the faces of my path outline, like a wall. In “geometry” this was happening with vertices. But now, in BufferGeometry and uvs the faces are a little different. What’s the proper way to convert this function now?

Previous Method:

``````var ngeometry = new THREE.SphereGeometry();

function assignUVs( geometry ) {

geometry.faceVertexUvs[ 0 ]  = [];
geometry.faces.forEach( function( face ) {
var uvs = [];
var ids = [ 'a', 'b', 'c'];
for( var i = 0; i < ids.length; i++ ) {
var vertex = geometry.vertices[ face[ ids[ i ] ] ].clone();
var n = vertex.normalize();
var yaw = .5 - Math.atan( n.z, - n.x ) / ( 2.0 * Math.PI );
var pitch = .5 - Math.asin( n.y ) / Math.PI;
var u = yaw,
v = pitch;
uvs.push( new THREE.Vector2( u, v ) );
}
});
}

// then trace the points in my path
for( var i = 0; i < points.length; i++ ) {

ngeometry.vertices.push( points[ i ] ),
ngeometry.faces.push( new THREE.Face3( 0, i + 1, i  ));

}

assignUVs( ngeometry );
ngeometry.computeVertexNormals();

``````

Attempts:

``````var ngeometry = new THREE.SphereBufferGeometry().setFromPoints( positions );

function assignUVs( geometry ) {

const uvAttr = geometry.getAttribute( 'uv' );
const uvs = new THREE.Vector2();
for ( let i = 0; i < uvAttribute.count; i += 3 ) {

const uv = new THREE.Vector3( uvAttribute[ i ], uvAttribute[ i + 1 ], uvAttribute[ i + 2 ] );
uvAttribute[ i ]     = uv.x
uvAttribute[ i + 1 ] = uv.y
uvAttribute[ i + 2 ] = uv.z

var yaw = .5 - Math.atan( uv.z, - uv.x ) / ( 2.0 * Math.PI );
var pitch = .5 - Math.asin( uv.y ) / Math.PI;
var u = yaw,
v = pitch;
.... ?
}
}
``````

I know I’m making this harder than it is. I’m getting results but not what I want. My faces look like they are pile of jagged rocks.

Can you show us the desired result? I’m not sure I understand what you mean by just drawing the faces of a path outline.

Sure. This is a model I created in r115. I converted the model but lost the walls on my countries. I was drawing the walls as a separate mesh using the xyz points from my country path.

I did this by assigning the path as faces to a spheregeometry. Of course the old method iterates over the vertices which dont exist in buffergeometry and the faces array also doesnt exist. How do I do this in current method? (r133)

Oh, also, the dataSet I’m using for the country data has points for (0,0,0) where a line ends. So all of my vertices in my geometry start from 0 and go outward. Obviously im drawing a lot of face I dont need. If I remove the (0,0,0) then I get a continuous line with no stops which also is not desirable. I’ll create another post for that though if I cant figure it out. For now, how to draw the path as walls on my SphereBufferGeometry.fromPoints()?

Thank You!

You can still access the vertices by getting the `"position"` bufferAttribute.

``````const geom = new THREE.SphereBufferGeometry(20.1, 200, 200);

// This gets the array of all positions [x, y, z, x, y, z, x, y z,...]
const positions = geom.getAttribute("position").array;

// This gets # of vertices
const vertexCount = geom.getAttribute("position").count;

// We'll store each vertex in this Vec3
const singleVertex = new THREE.Vector3();

// Each loop counts up by 3
for (let i3 = 0; i < vertexCount; i3 +=3) {
singleVertex.set(
positions[i3 + 0],
positions[i3 + 1],
positions[i3 + 2]
);

console.log(singleVertex.toArray().toString());
}
``````

Once you have the vertex positions, you could get each face by reversing the method used to create them. For example, when you have 4 vertices `a, b, c, d`, then face1 is made up of the `a, b, d` triangle and face2 is `b, c, d`:

``````const faces = geom.getIndex().array;

const a = 0, b = 1, c = 2, d = 3;
// 1st triangle
faces[a]
faces[b]
faces[d]

// 2nd triangle
faces[b]
faces[c]
faces[d]

// ... etc
``````

I didn’t get this line. You create an indexed buffer geometry for ~40K vertices, then re-write its `position` attribute with new values, and I doubt that it has the same amount of vertices; but `index` of the geometry is intact Highly likely you’ll get a very weird visual result.

Hello. Well actually youre right, I copied a piece of code for the example. The geometry I’m actually using, and the one from the previous model have no size or vertices. It eventually comes from what I put into it with the array. The one in use is just SphereBufferGeometry(); Sorry about that, I’ll fix the post.

Original Code:

``````ngeometry = new THREE.SphereGeometry();

...

for ( let feature in ... ) {

geoFeature = geojson.features[ ...];
coordinates = geoFeature.geometry.coordinates;

for ( let coordinate... ) {

multipolygons = coordinates[ ... ];
polygons = coordinates[ ... ];

for ( let coord in multipolygons ){

linePoint = returnSphericalCoordinates( [[ ... ], multipolygons[ ... ]], distance );
lineInnerPoint = returnSphericalCoordinates( [ ],  ], radius );
if( !isNaN( linePoint.x ) && !isNaN( linePoint.y ) && !isNaN( linePoint.z ) )

lineGeometry.vertices.push( linePoint );
point = new THREE.Vector3( lineInnerPoint.x, lineInnerPoint.y, lineInnerPoint.z );
points.push( lineInnerPoint );
}

for ( let coord in polygons ){

linePoint = returnSphericalCoordinates( [ polygons[ coord ][ 1 ], polygons[ coord ][ 0 ] ], distance );
lineInnerPoint = returnSphericalCoordinates( [ polygons[ coord ][ 1 ], polygons[ coord ][ 0 ] ], 209 );
if( !isNaN( linePoint.x ) && !isNaN( linePoint.y ) && isNaN( linePoint.z ) )
lineGeometry.vertices.push( linePoint );
point = new THREE.Vector3( lineInnerPoint.x, lineInnerPoint.y, lineInnerPoint.z );
points.push( lineInnerPoint );
}
}
}
}
for( var i = 0; i < points.length; i++ ) {

ngeometry.vertices.push( points[ i ] ),
ngeometry.faces.push( new THREE.Face3( 0, i + 1, i  ));

}

assignUVs( ngeometry );
ngeometry.mergeVertices();
ngeometry.computeVertexNormals();

var nline = new THREE.Mesh( ngeometry, globeMaterial );
nline.rotation.y = Math.PI;
nline.position.set( 0, 0, 0 );
nline.scale.set( 1, 1, 1 );

``````

I was attempting to avoid iterating over the points by creating the geometry from points and then assign the faces along its vertices ( positions ). Is that possible? Or do I have to literally retrace the points and create from the point array?

A triplet of numbers in `.index` defines a face by indices of vertices. That’s what @marquizzo above said.
Or, without `index`, a triplet of vertices defines a face.

This is great and thank you! I think I had gotten to this point:

i.e. -

``````    const position = geometry.getAttribute( 'position' );
const uvs = new THREE.Vector2();
for ( let i = 0; i < position.count; i += 3 ) {

const uv = new THREE.Vector3( position[ i ], position[ i + 1 ], position[ i + 2 ] );
position[ i ]     = uv.x
position[ i + 1 ] = uv.y
position[ i + 2 ] = uv.z
``````

However, if I create the geometry from points can I then not just assign the faces to the geometry? Or do I have to literally iterate over each point and create the faces? Is there an easier way to do this? In the original example I set the faces, and the geometry, at the same time, per each point of my point array. However, if instead I use `SphereBufferGeometry().fromPoints( pointsArray );` then can I just skip the iteration and simply assign faces ( a.k.a - material) to its geometry? Is there a way to do that? If I set geometry from points I should be able to just assign a material to the mesh, no? As a 2D vector instead of a Vector3, that way I only get the faces on the edges. Right?

So, how do I set the faces to the geometry as a 2D vector so I only get the side faces? Iteration only?

@prisoner849 as well.

I’m sorry, what I think in my head, and what comes out, sometimes arent the same. I overthink what I am trying to say. Thanks for your patience. I already have the faces of the countries as a separate layer on my model. I dont want to draw the front faces of the countries. I only want to draw the sides. So a mesh of only the side faces of the geometry. If I create my geometry `fromPoints( points )`, then the geometry is technically the path Im looking for (I think) so then I should be able to assign a material to that geometry that only applies the “2D” faces to that?

There, I think I said that right. I was thinking that I there might be a way to just apply the material to the geometry and not have to iterate over each index[ i * 3 ] and apply faces one-by-one like before.

So the faces are Vector3() of course but like

`const uv = new THREE.Vector2( a, b );`

and a face would be `Vector3( uv.x, uv.y, 0 )`. z will always be 0; All the faces are then vertical from 0;

You don’t have to index your vertices. Indexing just lets you re-use vertices to make your arrays smaller and more efficient, but they’re not mandatory. For example:

Face1: a, b, d
Face2: b, c, d

Face1: a, b, c
Face2: d, e, f

The benefits of indexing become greater when you’re dealing with meshes that create a grid, because you can re-use a vertex many times. But it’s not mandatory.

@marquizzo - I have the faces. How do I apply the faces now?

``````   var ngeometry = new THREE.SphereBufferGeometry().setFromPoints( points ) ;

// This gets the array of all positions [x, y, z, x, y, z, x, y z,...]
const positions1 = ngeometry.getAttribute("position").array;
const uvArr = ngeometry.getAttribute("uv").array;
const vertexCounts = ngeometry.getAttribute("position").count;

// We'll store each vertex in this Vec3
const singleVertex = new THREE.Vector3();

// Each loop counts up by 3
for (let i3 = 0; i3 < vertexCounts; i3 +=3) {
var uvs = [];
singleVertex.set(
positions1[i3 + 0],
positions1[i3 + 1],
positions1[i3 + 2]
);

var vertex = singleVertex.clone();
var n = vertex.normalize();
var yaw = .5 - Math.atan( n.z, - n.x ) / ( 2.0 * Math.PI );
var pitch = .5 - Math.asin( n.y ) / Math.PI;
var u = yaw,
v = pitch;
uvs.push( new THREE.Vector2( u, v ) );

}
// uvArr.push( uvs ); // <-- apply faces ???
ngeometry.computeVertexNormals();
``````

Used to be

``````geometry.faceVertexUvs[ 0 ]  = [];
geometry.faceVertexUvs[ 0 ].push( uvs );
``````

What’s the replacement for that?