# Is computeVertexNormals working correctly?

I have a cylinder setup, it starts with smooth transition between vertical faces: after computeVertexNormals() is applied, the smooth transition remains, except the edge between the first and the last face, where there are 3 different normals instead of 2 (or 3 matching in to 2 before): this creates a jump between normals on more complex geometries, where there shouldn’t be any:

It is actually not intended to recompute normals of geometry generators since they are often computed analytically to get correct result. Using `computeVertexNormals()` will undo this effort and produce unexpected results.

In this particular case, the seam occurs since the vertices are duplicated at the edge because different texture coordinates are required. So because the body has no continuous geometry, `computeVertexNormals()` can’t be used.

2 Likes

For special geometries, you should always calculate the normals yourself.
However, I sometimes use `.computeVertexNormals( )` when only a few changes are needed afterwards.

From the Collection of examples from discourse.threejs.org : MultiFormGeometry
see
`view-source:https://hofk.de/main/discourse.threejs/2022/MultiFormGeometry/multiFormGeometryStatic.js`

line 473

``````       g.computeVertexNormals( );

// calculate new average normals at seam ( smooth shading )

for ( let i = 0; i < hss; i ++ ) { // height

}

if( wb ) {  // calculate new average normals at bottom  ( smooth shading )

for( let j = 0; j < rss ; j ++ ) { // bottom

smoothEdge( j, rss * hss + 1 + j );

}

}

if( wt ) {  // calculate new average normals at top ( smooth shading )

for( let j = 0; j < rss ; j ++ ) { // top

}
}

function smoothEdge( idxa, idxb ) {

const v3a = new THREE.Vector3( );
const v3b = new THREE.Vector3( );
const v3  = 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 ) );

g.attributes.normal.setXYZ( idxa, v3.x, v3.y, v3.z );
g.attributes.normal.setXYZ( idxb, v3.x, v3.y, v3.z );

}
``````

Yeah, I realized that shape agnostic algorithms will not work, didn’t think about it much before. I wrote some code for updating normals for certain shapes after twisting and profiling them along main axes, that’s what I needed. Instead of running computeVertexNormals and then fixing seams, I took a different approach, where I’m reusing original normals, this way I’m less bound to how the geometry was generated and where the seam are.

Here is an example for CylinderGeometry: 