three.js: geometry.computeVertexNormals() not working for extruded geometry

Description of the problem

geometry.computeVertexNormals() not working for extruded geometry created using absarc.

Best explained with pictures and fiddle.

image

image

https://jsfiddle.net/k2r4cqnh/2/

I have also tried geometry.computeFaceNormals and shading: SmoothShading but no dice!

You get the same problem with the shape with/without a hole.

Three.js version
  • r81
Browser
  • All of them
OS
  • Windows

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 22 (2 by maintainers)

Most upvoted comments

@WestLangley - I agree that we shouldn’t modify geometry.computeVertexNormals() directly but there should be a THREE method to achieve smoothing the faces of an extruded shape without artefacts. I am now using a smoothExtrudedGeometry() function based on the discussion in this thread. A nice example of this is the elimination of some bezier scaring on some 3D extruded helical gears. See before and after below…

before smoothExtrudedGeometry() image

after smoothExtrudedGeometry() image

three.js is a rendering engine, not a modeling tool. I think the best solution is for you to develop your model using modeling software, and import it into three.js.

I think the above image of gears shows that THREE.js can be a fantastic direct modelling tool. Given the many parameters used to describe certain geometries (such as gear teeth) it would not be practical to develop templates of such models if you want to dynamically change their attributes based on some user input. Or have I misunderstood something about THREE.js?

@henryJack if you add after geometry.computeVertexNormals();

for ( var i = 0; i < geometry.faces.length; i ++ ) {
    var face = geometry.faces[ i ];
    if (face.materialIndex == 1 ) {
        for ( var j = 0; j < face.vertexNormals.length; j ++ ) {
            face.vertexNormals[ j ].z = 0;
            face.vertexNormals[ j ].normalize();
        }
    }
}

you will see that the ring is smooth. I can’t remember how to make the sides flat though…

image

There are still a lot of visible scars in that geometry. By computing the vertex normals you should be able to get the geometry as smooth as the native cylinder and torus geometries without having to use excessive numbers of segments

image

it would not be practical to develop templates of such models if you want to dynamically change their attributes based on some user input

@henryJack Good point.

Like i said before, there is maybe a way to create an ExtrudeBufferGeometry that is a little bit more flexible than the current implementation.

@Mugen87 Yes. At a minimum, since material.shading = THREE.FlatShading can be used to render faceted edges, we can create an ExtrudeBufferGeometry and make sure to share vertices on the edge and bevel. That is, think of the entire edge and bevel as a warped CylinderBufferGeometry. That way, computeVertexNormals() can be applied to the edge, and the edge can appear smooth everywhere. The front and back faces (and normals) would have to be handled separately in the constructor.

I agree this would be a nice enhancement. It is not completely flexible, but it satisfies complaints by users of edges not being smooth.

@henryJack geometry.computeVertexNormals() is designed to be applied to any arbitrary geometry. We can’t modify the method to accommodate your specific geometry.

Also, be aware that not all users are extruding a circle. If you were extruding the letter D, you would not want smooth normals everywhere.

three.js is a rendering engine, not a modeling tool. I think the best solution is for you to develop your model using modeling software, and import it into three.js.

Maybe we can try to solve this problem if we create an ExtrudeBufferGeometry in the future.

Closing due to age. If there is an issue in a recent three.js revision, please file a new issue.

Hi @zz85 and @henryJack

You can make the sides flat with a THREE.MultiMaterial.

var material = new THREE.MultiMaterial([
    new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.FlatShading } ), // front
    new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.SmoothShading } ) // side
]);

var extrudeSettings = {
  amount: 3,
  bevelEnabled: false,
  curveSegments: 40,
  material: 0,
  extrudeMaterial: 1
};

See https://jsfiddle.net/k2r4cqnh/5/

image