Search code examples
javascripttypescriptthree.jsgltf

Threejs: How can one export with GLTFExporter an indexed geometry with draw range?


I have a specific problem, I would like to export an indexed geomtry that has a drawrange. Using the GLTFExporter, after having faced the issue with typescript integration (known issue apparently), I had the bad luck to discover that this was not implemented in the exporter:

// @TODO Indexed buffer geometry with drawRange not supported yet

https://github.com/mrdoob/three.js/blob/master/examples/js/exporters/GLTFExporter.js line 564

Checking the commit history showed me that the last update was 3 months ago and I don't think this is gonna come any time soon. I tried to remove the index buffer and rewrite my position bufferattribute array base on my draw range but I must do something wrong because it does not work, it simply breaks my geometry. Would any of you have a work around for me or some explainations on how to proceed with my geometry?

Thank you in advance.

EDIT:

My current work-around is to "de-index" my geometry for the export and keep the drawRange, this case is handled by the exporter. It is not ideal, and it forces me to recreate a full new geometry with new BufferAttributes. But since this operation is only done for the export, I can even have this process happening in an asynchronous way. I wish there was a better way.


Solution

  • As mentionned in my edit, I bypassed my problem by de-indexing of my geometry, it is not the best solution, but since I only need it for this export, here is how I proceeded:

    // original attributes
    const vertices  = geometryTmp.getAttribute("position");
    const normals  = geometryTmp.getAttribute("normal");
    const uv  = geometryTmp.getAttribute("uv");
    
    // new buffer arrays
    let verticesTmp = new Float32Array(3 * geometryTmp.index.array.length);
    let normalTmp = new Float32Array(3 * geometryTmp.index.array.length);
    let uvTmp = new Float32Array(2 * geometryTmp.index.array.length);
    
    
    let j = 0;
    for(let i = 0; i < verticesTmp.length; i += 3) {
        let index = geometryTmp.index.array[j];
        verticesTmp[i] = vertices.getX(index);
        verticesTmp[i+1] = vertices.getY(index);
        verticesTmp[i+2] = vertices.getZ(index);
    
        normalTmp[i] = normals.getX(index);
        normalTmp[i+1] = normals.getY(index);
        normalTmp[i+2] = normals.getZ(index);
        j++;
    
    }
    
    j = 0;
    for(let i = 0; i < uvTmp.length; i += 2) {
        let index = geometryTmp.index.array[j];
        uvTmp[i] = uv.getX(index);
        uvTmp[i+1] = uv.getY(index);
        j++;
    }
    
    let newGeomtry = new THREE.BufferGeometry();
    newGeomtry.addAttribute( 'position', new THREE.BufferAttribute( verticesTmp, 3 ) );
    newGeomtry.addAttribute( 'normal', new THREE.BufferAttribute( normalTmp, 3 ) );
    newGeomtry.addAttribute( 'uv', new THREE.BufferAttribute( uvTmp, 2 ) );
    
    newGeomtry.drawRange = geometryTmp.drawRange;
    mesh.geometry = newGeomtry;  
    
    // After I do that to all the meshes I need, them to a new THREE.Scene that will be given to the exporter with truncateDrawRange = true
    

    I hope it helps someone too.