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.

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!