flatShading on BufferGeometry (or imported model)

Hi guys!

I’m loading a GLTF model, the model was exported without normals (that increases 300% the file size), so I need to calculate here.

I need to get a flat shading on some meshes and smooth shading on other meshes. Smooth runs fine, but flat throws error.

model.traverse( (m) => {
    if (m.type == 'Mesh' /*|| m.isSkinnedMesh*/) {
        if ( m.name.indexOf('Fruit_m_') !== -1 ) {
            m.geometry.computeVertexNormals()
            m.material = fruits_mat
         } else {
            m.geometry.computeFlatVertexNormals()
            m.material = world_mat
         }
    }
})

In this link you can see it running. The fruits are smooth and the world needs to be flat shading.
http://hit.larealidadaumentada.com.co/

Any help?

Try it like so:

geometry = geometry.toNonIndexed();
geometry.computeVertexNormals():

Since a non indexed geometries shares no vertices between triangles, computing vertex normals result in a flat shaded mesh.

1 Like

This is the code but keep getting the same result

model.traverse( (m) => {
    if (m.type == 'Mesh' /*|| m.isSkinnedMesh*/) {
        if ( m.name.indexOf('Fruit_m_') !== -1 ) {
            m.geometry.computeVertexNormals()
            m.material = fruits_mat
         } else {
            m.geometry = m.geometry.toNonIndexed()
            m.geometry.computeVertexNormals()
            m.material = world_mat
         }
    }
})

This is how it shows


and this is how I need it to be rendered (Blender preview)

maybe try adding:

m.geometry.attributes.normal.needsUpdate = true;

That is not necessary when modifying geometry before the initial rendering. So it won’t help here.

Instead of recomputing normals, can you just set the flatShading property of world_mat to true?

That is not deprecated? anyway, neither works. And I can’t find the way. Heeeeeeeeeelp!

Why bufferGeometry hasn’t computeFlatVertexNormals?

My guess is that the tononindex doesn’t recalculate the normals- it simply copies them to the new vertices, so you are still seeing them look smoothed…

I think you’ll have to calculate the normals based on the face normal, however the only way I’ve found to do that is to use a THREE.Triangle like so:

function getFaceNormal(geometry, face ){
	let pos = geometry.attributes.position;
	let idx = geometry.index;

	let a = new THREE.Vector3(), 
		b = new THREE.Vector3(), 
		c = new THREE.Vector3(),
		returnNormal = new THREE.Vector3();

	let idxBase = face * 3;
	a.fromBufferAttribute( pos, idx.getX( idxBase + 0 ) );
	b.fromBufferAttribute( pos, idx.getX( idxBase + 1 ) );
	c.fromBufferAttribute( pos, idx.getX( idxBase + 2 ) );
	let tri = new THREE.Triangle( a, b, c );
	
	tri.getNormal( returnNormal );
	
	return returnNormal;
}

You’ll have to cycle through all the normals and set them , and then do the m.geometry.attributes.normal.needsUpdate = true;
after they have been calculated.

Makes sense. But how can I apply this to imported model when I cant reach faces? as far as I can go is Geometry.
image

You’d have to set the Attributes of the bufferGeometry…

such as:
m.geometry.attributes.normal.setXYZ( index, x, y, z );

and then after all them are set do:
m.geometry.attributes.normal.needsUpdate = true;

Geometry is removed in r125… Three.js doesn’t support that anymore, unfortunately.
They only support bufferGeometry now.

@MrMateo07

I found that in this moment we cant calculate faceNormals in bufferGeometry

This says that bufferGeometry is pretty outdated yet.

Face normals cannot be computed on BufferGeometry without converting the model to non indexed or to use an index buffer with one index per vertex. The two methods that @Mugen87 provided are the two correct ways to get get flat shading with BufferGeometry. There’s no reason to use now deprecated Geometry class.

anyway, neither works. And I can’t find the way. Heeeeeeeeeelp!

If using Material.flatShading = true and toNonIndexed with computeVertexNormals is not working then there must be another issue in your code. Please provide a js fiddle showing what you’re doing so it can be pointed out where the issue is.

1 Like

You are right and of course @Mugen87.

Inspecting everything I found the mistake. I was using a MeshBasicMaterial. Thats why

wasnt working.

Thanks for your time!