Search code examples
three.jsgeometrymeshsmoothing

How to smooth mesh triangles in STL loaded BufferGeometry


I´m trying to load some STL files using Three.js. The models are loaded correctly, but there are too many triangles that I would like to merge/smooth.

I had successfully applied smooth loading terrains in other 3D formats, but I can´t do it with the BufferGeometry that results from loading an STL file with the STLLoader.

enter image description here _

var material = new THREE.MeshLambertMaterial( { ... } );
var path = "./models/budah.stl";
var loader = new THREE.STLLoader();
loader.load( path, function ( object ) {
                object.computeBoundingBox();
                object.computeBoundingSphere();
                object.computeFaceNormals();
                object.computeVertexNormals();
                object.normalizeNormals();
                object.center();

                // Apply smooth
                var modifier = new THREE.SubdivisionModifier( 1);
                var smooth = smooth = object.clone();
                smooth.mergeVertices();
                smooth.computeFaceNormals();
                smooth.computeVertexNormals();
                modifier.modify( smooth );
                scene.add( smooth );
});

This is what I tried, it throws an error: Uncaught TypeError: smooth.mergeVertices is not a function

If I comment the "mergeVertices()" line, what I get is a different error: Uncaught TypeError: Cannot read property 'length' of undefined in SubdivisionsModifier, line 156.

It seems that the sample codes I´m trying are outdated (this is happenning a lot recently due to the massive changes in the Three.JS library). Or maybe I´m forgetting something. The fact is that the vertices seems to be null..?

Thanks in advance!


Solution

  • It seems I was looking in the wrong direction: smoothing the triangles has nothing to do with the SubdivisionsModifier... What I needed was easier than that, just compute the vertex BEFORE applying the material, so it can use SmoothShading instead of FlatShading (did I got it right?).

    The problem here was that the BufferGeometry returned by the STLLoader has not calculated vertices/vertex, so I had to do it manually. After that, apply mergeVertices() just before computeVertexNormals() and voilà! The triangles dissappear and everything is smooth:

    var material = new THREE.MeshLambertMaterial( { ... } );
    var path = "./models/budah.stl";
    var loader = new THREE.STLLoader();
    loader.load( path, function ( object ) {                
                    object.computeBoundingBox();
                    object.computeVertexNormals();
                    object.center();
                    ///////////////////////////////////////////////////////////////
    
                    var attrib = object.getAttribute('position');
                    if(attrib === undefined) {
                        throw new Error('a given BufferGeometry object must have a position attribute.');
                    }
                    var positions = attrib.array;
                    var vertices = [];
                    for(var i = 0, n = positions.length; i < n; i += 3) {
                        var x = positions[i];
                        var y = positions[i + 1];
                        var z = positions[i + 2];
                        vertices.push(new THREE.Vector3(x, y, z));
                    }
                    var faces = [];
                    for(var i = 0, n = vertices.length; i < n; i += 3) {
                        faces.push(new THREE.Face3(i, i + 1, i + 2));
                    }
    
                    var geometry = new THREE.Geometry();
                    geometry.vertices = vertices;
                    geometry.faces = faces;
                    geometry.computeFaceNormals();              
                    geometry.mergeVertices()
                    geometry.computeVertexNormals();
    
                    ///////////////////////////////////////////////////////////////
                    var mesh = new THREE.Mesh(geometry, material);
    
                    scene.add( mesh );
    });
    

    enter image description here