2
votes

I'm importing .3DS models into Blender 2.72b, then exporting them with the Three.js import/export addon. The models have multiple geometry 'islands' (separate groups of connected faces and vertices), each with its own material. I'd like to be able to pair each material with its corresponding island, without having to create separate THREE.Geometry objects. After some digging, I found this question which suggests using a THREE.MeshFaceMaterial to achieve multiple materials for one object. The only problem is that the geometry in that example is a simple cube, whereas my models have hundreds of faces spread across 2-5 islands.

Does Three.js have functionality for identifying geometry 'islands' in a mesh?

2

2 Answers

2
votes

No. three.js does not have functionality for identifying geometry 'islands' in a mesh.

When using MeshFaceMaterial, WebGLRenderer breaks the geometry into chunks anyway -- one chunk for each material. It does that because WebGL supports one shader per geometry.

I would not merge all your geometries, and then use MeshFaceMaterial, only to have the renderer break the single geometry apart.

You can merge geometries that share a single material if you wish.

three.js r.69

0
votes

I tried with a function but still is not accurate, it produce more geometries than non connected geometries:

If somebody could have a look on it, it would be grate.

function groupGeometryIntoNonConnectedGeometries(geometry) {
        const material = new THREE.MeshBasicMaterial({
            side: THREE.DoubleSide,
            vertexColors: THREE.VertexColors
        });
        let geometryArray = [];
        const indexArray = geometry.index.array;
        const positionArray = geometry.attributes.position.array;
        const positionCount = geometry.attributes.position.count;
        const color = new THREE.Vector3(geometry.attributes.color.array[0], geometry.attributes.color.array[1], geometry.attributes.color.array[2]);
        const totalTriangles = indexArray.length / 3;
        let geometryCount = 0;
        let indexValueAlreadyVisited = new Uint8Array(indexArray.length);   
        let structure = [];
            /*
             * indexValue: {
             *  child: [ [indexval0, indexval1], [] ],
             *  parent: null
             * }
             */
        // Initialize Structure:
        for (var vextexIdx=0; vextexIdx<positionCount; vextexIdx++) {
            structure[vextexIdx] = {
                child: [],
                parent: null
            }
        }   
        
        for (idx=0; idx<totalTriangles; idx++) {
            const geoIndex1 = indexArray[idx*3];
            const geoIndex2 = indexArray[idx*3+1];
            const geoIndex3 = indexArray[idx*3+2];
            const triangleIndexVertexArray = [ geoIndex1, geoIndex2, geoIndex3 ].sort(function(a, b) { 
                return a - b; 
            });
            structure[ triangleIndexVertexArray[0] ].child.push(triangleIndexVertexArray[1], triangleIndexVertexArray[2]);
            structure[ triangleIndexVertexArray[1] ].parent = triangleIndexVertexArray[0];
            structure[ triangleIndexVertexArray[2] ].parent = triangleIndexVertexArray[0];              
        }
        let count = 0;
        let currentCount = 0;
        let geometryStructureArray = [];
        
        for (let strIdx=0; strIdx<structure.length; strIdx++) {
            if (structure[strIdx].parent == null) {
                currentCount = count;
                geometryStructureArray[currentCount] = {
                    name: "G_" + currentCount,
                    indexMap: {},
                    currentIndex: 0,
                    indexArray: [],
                    positionArray: [],
                    colorArray: []
                };
                count += 1;
            }
            if (structure[strIdx].child.length > 0) {
                const childLen = structure[strIdx].child.length / 2;
                for (let childIdx=0; childIdx<childLen; childIdx++) {
                    const vertexIndex0 = strIdx;
                    const vertexIndex1 = structure[strIdx].child[childIdx*2];
                    const vertexIndex2 = structure[strIdx].child[childIdx*2+1];
                    const v0 = new THREE.Vector3( positionArray[strIdx*3], positionArray[strIdx*3+1], positionArray[strIdx*3+2] );
                    const v1 = new THREE.Vector3( positionArray[vertexIndex1*3], positionArray[vertexIndex1*3+1], positionArray[vertexIndex1*3+2] );
                    const v2 = new THREE.Vector3( positionArray[vertexIndex2*3], positionArray[vertexIndex2*3+1], positionArray[vertexIndex2*3+2] );
                    
                    // check vertex0
                    if (geometryStructureArray[currentCount].indexMap[vertexIndex0] == undefined) {
                        geometryStructureArray[currentCount].indexMap[vertexIndex0] = geometryStructureArray[currentCount].currentIndex;
                        geometryStructureArray[currentCount].indexArray.push(geometryStructureArray[currentCount].currentIndex);
                        geometryStructureArray[currentCount].positionArray.push(v0.x, v0.y, v0.z);
                        geometryStructureArray[currentCount].colorArray.push(color.x, color.y, color.z);
                        geometryStructureArray[currentCount].currentIndex += 1;
                    } else {
                        geometryStructureArray[currentCount].indexArray.push(geometryStructureArray[currentCount].indexMap[vertexIndex0]);
                    }
                    
                    // check vertex1
                    if (geometryStructureArray[currentCount].indexMap[vertexIndex1] == undefined) {
                        geometryStructureArray[currentCount].indexMap[vertexIndex1] = geometryStructureArray[currentCount].currentIndex;
                        geometryStructureArray[currentCount].indexArray.push(geometryStructureArray[currentCount].currentIndex);
                        geometryStructureArray[currentCount].positionArray.push(v1.x, v1.y, v1.z);
                        geometryStructureArray[currentCount].colorArray.push(color.x, color.y, color.z);
                        geometryStructureArray[currentCount].currentIndex += 1;
                    } else {
                        geometryStructureArray[currentCount].indexArray.push(geometryStructureArray[currentCount].indexMap[vertexIndex1]);
                    }
                    
                    // check vertex1
                    if (geometryStructureArray[currentCount].indexMap[vertexIndex2] == undefined) {
                        geometryStructureArray[currentCount].indexMap[vertexIndex2] = geometryStructureArray[currentCount].currentIndex;
                        geometryStructureArray[currentCount].indexArray.push(geometryStructureArray[currentCount].currentIndex);
                        geometryStructureArray[currentCount].positionArray.push(v2.x, v2.y, v2.z);
                        geometryStructureArray[currentCount].colorArray.push(color.x, color.y, color.z);
                        geometryStructureArray[currentCount].currentIndex += 1;
                    } else {
                        geometryStructureArray[currentCount].indexArray.push(geometryStructureArray[currentCount].indexMap[vertexIndex2]);
                    }
                    
                }
            }   
        }
        
        // Convert to geometryArray:
        const geometryStructureArrayLen = geometryStructureArray.length;
        const object3d = new THREE.Object3D();
        
        for (let geoIdx=0; geoIdx<geometryStructureArrayLen; geoIdx++) {
            const geo = new THREE.BufferGeometry();
            geo.name = "G_" + geoIdx;
            const geoPositions = new Float32Array(geometryStructureArray[geoIdx].positionArray);
            const geoColors = new Float32Array(geometryStructureArray[geoIdx].colorArray);
            const geoIndices = new Uint32Array(geometryStructureArray[geoIdx].indexArray);
            //console.log(geoIdx, "geoPositions: ", geoPositions);
            //console.log(geoIdx, "geoColors: ", geoColors);
            //console.log(geoIdx, "geoIndices: ", geoIndices);
            geo.index = new THREE.BufferAttribute(geoIndices, 1, false);
            
            geo.attributes.position = new THREE.BufferAttribute(geoPositions, 3, false);
            geo.attributes.color = new THREE.BufferAttribute(geoColors, 3, true);
            geo.computeBoundingSphere();
            geo.computeBoundingBox();
            
            const mesh = new THREE.Mesh(geo, material);
            mesh.name = "M_" + geoIdx;
            object3d.add(mesh);
        }
        //return [structure, geometryStructureArray, object3d, count];
        return object3d;
    }

Best regards