Duplicate vertices in buffergeometry

I am testing out getting vertex normals from gltf models. My understanding is that there is one normal per vertex, however when I draw them with arrows, I’m getting 3 normals per vertex. (image below)

My understanding is that the BufferGeometry assembled from the GLTF is indexed right? So surely there should only be 8 vertices and vertex normals, that are grabbed using the index to make triangles. Why do I have 24 vertices and vertex normals?

It seems like there is something fundamental that I can’t get my head around…

Hi stickyvectors
I think the faces of your box are exported detached to have sharp edges.

1 Like

As @alessandro_guarino mentions, this is in order to provide sharp edges. You are correct that each vertex can have only one normal vector, and so hard edges require 2 or more vertices — with different normals — at the same position.

A BufferGeometry assembled by GLTFLoader may or may not be indexed, depending on the glTF file… I would guess that most tools create indexed glTF files by default, on the assumption that at least some vertices may be shared, but it probably doesn’t matter much for this box.

1 Like

Possibly the example contributes to the understanding of the matter.

From the Collection of examples from discourse.threejs.org


2021-05-11 10.42.04

The vertices and normals can be determined in various ways to achieve appropriate effects. See the source code of the example.

function generateCap( top ) { ... }

if ( wTop && !flatTop ) { // calculate new normals at top seam
	for( let j = 0; j <= g.radial; j ++ ) {
		smoothEdge( ( g.radial + 1 ) * ( g.vertical + 1 ) + 1 + j, j );

function smoothEdge( idxa, idxb ) {
	let v3a = new THREE.Vector3( );
	let v3b = new THREE.Vector3( );
	v3a.set( g.attributes.normal.getX( idxa ), g.attributes.normal.getY( idxa ), g.attributes.normal.getZ( idxa ) );
	v3b.set( g.attributes.normal.getX( idxb ), g.attributes.normal.getY( idxb ), g.attributes.normal.getZ( idxb ) );
	v3.addVectors( v3a, v3b ).normalize( );
	g.attributes.normal.setXYZ( idxa, v3.x, v3.y, v3.z );
	g.attributes.normal.setXYZ( idxb, v3.x, v3.y, v3.z );