Function to create a indexed Geometry from a non-indexed

normals
buffergeometry

#1

Since i already posted the half snippet, this patches THREE.BufferGeometry with a function to create a indexed one from a non-indexed. A new BufferGeometry is returned.

A indexed geometry reduces the data of all attributes and will generally perform better, also computeVertexNormals can be called only on indexed geometries to compute smooth normals.

I haven’t added the ability to detect wanted disconnected faces, this is mostly relevant if different attribute values are required at the same position like UV coordinates, it causes them to merge yet like in this example.

THREE.BufferGeometry.prototype.toIndexed = function() {

    let prec = 0;
    let list = [];
    let vertices = {};

    function store(x, y, z, v) {


        const id = Math.floor( x * prec ) + '_' + Math.floor( y * prec ) + '_'  + Math.floor( z * prec );

        if ( vertices[id] === undefined ) {

            vertices[id] = list.length;


            list.push(v);

        }

        return vertices[id];

    }

    function indexBufferGeometry(src, dst) {



        const position = src.attributes.position.array;

        const faceCount = ( position.length / 3 ) / 3;


        const type = faceCount * 3 > 65536 ? Uint32Array : Uint16Array;

        const indexArray = new type(faceCount * 3);

        for ( let i = 0, l = faceCount; i < l; i ++ ) {

            const offset = i * 9;

            indexArray[i * 3    ] = store(position[offset], position[offset + 1], position[offset + 2], i * 3);
            indexArray[i * 3 + 1] = store(position[offset + 3], position[offset + 4], position[offset + 5], i * 3 + 1);
            indexArray[i * 3 + 2] = store(position[offset + 6], position[offset + 7], position[offset + 8], i * 3 + 2);

        }

        dst.index = new THREE.BufferAttribute(indexArray, 1);



        const count = list.length;

        for ( let key in src.attributes ) {

            const src_attribute = src.attributes[key];
            const dst_attribute = new THREE.BufferAttribute(new src_attribute.array.constructor(count * src_attribute.itemSize), src_attribute.itemSize);

            const dst_array = dst_attribute.array;
            const src_array = src_attribute.array;

            switch ( src_attribute.itemSize ) {
                case 1:

                    for ( let i = 0, l = list.length; i < l; i ++ ) {

                        dst_array[i] = src_array[list[i]];

                    }


                    break;
                case 2:

                    for ( let i = 0, l = list.length; i < l; i ++ ) {

                        const index = list[i] * 2;

                        const offset = i * 2;

                        dst_array[offset] = src_array[index];
                        dst_array[offset + 1] = src_array[index + 1];

                    }


                    break;
                case 3:

                    for ( let i = 0, l = list.length; i < l; i ++ ) {

                        const index = list[i] * 3;

                        const offset = i * 3;

                        dst_array[offset] = src_array[index];
                        dst_array[offset + 1] = src_array[index + 1];
                        dst_array[offset + 2] = src_array[index + 2];


                    }

                    break;
                case 4:

                    for ( let i = 0, l = list.length; i < l; i ++ ) {

                        const index = list[i] * 4;

                        const offset = i * 4;

                        dst_array[offset] = src_array[index];
                        dst_array[offset+ 1] = src_array[index + 1];
                        dst_array[offset + 2] = src_array[index + 2];
                        dst_array[offset + 3] = src_array[index + 3];


                    }

                    break;
            }


            dst.attributes[key] = dst_attribute;


        }


        dst.boundingSphere = new THREE.Sphere;
        dst.computeBoundingSphere();

        dst.boundingSphere = new THREE.Box3;
        dst.computeBoundingBox();



        // Release data

        vertices = {};
        list = [];

    }

    return function( precision ) {

        prec = Math.pow(10,  precision || 6 );

        const geometry = new THREE.BufferGeometry;

        indexBufferGeometry(this, geometry);

        return geometry;

    }

}();