matlabthree.jsmeshbuffer-geometry

Why does my buffer geometry fail when I try to load in vertices, faces and normal from .mat file?


I want to load in my matlab geometry into my three.js scene. My 3D data is saved in a struct .mat file which contains .vertices, .faces, .VertexNormals and .VertexColorData arrays. I am able to load it into JavaScript and use buffer geometry and set attributes to store the data into a mesh geometry.

                var keyName = keysArray[0];

                meshGeometry = new THREE.BufferGeometry();

                var index = 0;
                var positions = new Float32Array(bfjson.data[keyName].vertices.length * 3);
                for (let i = 0; i < bfjson.data[keyName].vertices.length; i++) {
                    positions[index++] = bfjson.data[keyName].vertices[i][0];
                    positions[index++] = bfjson.data[keyName].vertices[i][1];
                    positions[index++] = bfjson.data[keyName].vertices[i][2];
                }
                meshGeometry.setAttribute(
                    'position',
                    new THREE.BufferAttribute(positions, 3));
                
                
                var index = 0;              
                var vectornormals = new Float32Array(bfjson.data[keyName].VertexNormals.length * 3);
                for (let i = 0; i < bfjson.data[keyName].VertexNormals.length; i++) {
                    vectornormals[index++] = bfjson.data[keyName].VertexNormals[i][0];
                    vectornormals[index++] = bfjson.data[keyName].VertexNormals[i][1];
                    vectornormals[index++] = bfjson.data[keyName].VertexNormals[i][2];       
                }
                meshGeometry.setAttribute(
                    'normal',
                    new THREE.BufferAttribute(vectornormals, 3));
                 
                    
                var index = 0;
                //var faces = new Uint16Array(bfjson.data[keyName].faces.length * 3);
                var faces = [];
                for (let i = 0; i < bfjson.data[keyName].faces.length; i++) {
                    faces[index++] = bfjson.data[keyName].faces[i][0];
                    faces[index++] = bfjson.data[keyName].faces[i][1];
                    faces[index++] = bfjson.data[keyName].faces[i][2];    
                }
                meshGeometry.setIndex(faces);
                
                // default color attribute
                const colors = [];

                for (let i = 0, n = meshGeometry.attributes.position.count; i < n; ++i) {

                    colors.push(1, 1, 1);
                }

            meshGeometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));


            for (let i = 0; i < bfjson.data[keyName].CData.length; i++) {

                CData[i] = (bfjson.data[keyName].CData[i]);

            }

            meshGeometry.setAttribute('perfusion', new THREE.Float32BufferAttribute(CData, 1)); 
            mesh.geometry = meshGeometry;
            updateColors();
   

The vertex coloring works fine. However, I end up with mesh with index faces or normal not connecting into a normal surface.

mesh with index faces or normal not connecting up into a normal surface.

I am not sure what I am doing wrong. I will be extremely grateful for any help provided.

Edit-- I have made a jsfiddle to help. https://jsfiddle.net/marieO/5zdhsk78/68/

But you need to download the .mat file first then upload it to the scene.


Solution

  • Thanks for posting a working example with the steps needed to reproduce the error. It makes it much easier to help.

    You have 652 vertices in your Matlab geometry. When using .setIndex(), these indices have to be in the [0, 651] range, because JavaScript arrays start at index 0. However, your faces data ranges from [1, 652], which means all your triangles are off by 1 vertex.

    This is easily solvable by adding a -1 when assigning the index:

    var index = 0;
    var faces = [];
    
    for (let i = 1; i < bfjson.data[keyName].faces.length; i++) {
        faces[index++] = bfjson.data[keyName].faces[i][0] - 1;
        faces[index++] = bfjson.data[keyName].faces[i][1] - 1;
        faces[index++] = bfjson.data[keyName].faces[i][2] - 1;
    }
    
    meshGeometry.setIndex(faces);
    

    Result: enter image description here