3

I'd like to move a piece of my code in which i build a THREE.Geometry object to a HTML5 Web Worker.

Since i don't want to serialize it to a string (for obvious performance purposes), i'd like to convert it to a Transferable Object like ArrayBuffer, File or Blob so i can pass it "by reference".

Do you know a efficient way to convert a THREE.Geometry to one of those objects ?

Sebastien
  • 682
  • 1
  • 14
  • 26

1 Answers1

7

The most efficient way is to use the existing geometry buffers such as:

geometryGroup.__vertexArray
geometryGroup.__normalArray

They are created in WebGLRenderer.initMeshBuffers.

How it works:

  1. Create a Worker and import three.js using importScripts("/js/lib/mrdoob-three.js-35db421/build/three.js");

  2. In the worker you create another instance of the geometry you want to process.

  3. Trigger one initial rendering in the main thred renderer.render(scene, camera); now the buffers are available...

  4. Send the required buffers from the main thread to the worker

  5. Do the hard work on the geometry at the worker thread

  6. Manually (there is no support for that in threejs) fill the required buffers (see WebGLRenderer.setMeshBuffers) e.g.:

    var vertexArray = new Float32Array(vertexBuffer);
    var normalArray = new Float32Array(normalBuffer);
    
    var vertices : Array = geometry.vertices;
    var obj_faces : Array = geometry.faces;
    
    var offset = 0;
    var offset_normal = 0;
    
    for (f in 0...obj_faces.length) {
    
        var face = obj_faces[ f ];
    
        var v1 = vertices[ face.a ];
        var v2 = vertices[ face.b ];
        var v3 = vertices[ face.c ];
        var v4 = vertices[ face.d ];
    
        vertexArray[ offset ]     = v1.x;
        vertexArray[ offset + 1 ] = v1.y;
        vertexArray[ offset + 2 ] = v1.z;
    
        vertexArray[ offset + 3 ] = v2.x;
        vertexArray[ offset + 4 ] = v2.y;
        vertexArray[ offset + 5 ] = v2.z;
    
        vertexArray[ offset + 6 ] = v3.x;
        vertexArray[ offset + 7 ] = v3.y;
        vertexArray[ offset + 8 ] = v3.z;
    
        vertexArray[ offset + 9 ]  = v4.x;
        vertexArray[ offset + 10 ] = v4.y;
        vertexArray[ offset + 11 ] = v4.z;
    
        offset += 12;
    }
    
  7. send the buffers back to the main thread and update the geometry there:

    var geometryGroup = mesh.geometry.geometryGroupsList[0];
    
    var _gl = renderer.context;
    _gl.bindBuffer(_gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
    _gl.bufferData(_gl.ARRAY_BUFFER, transferVertexArray, _gl.DYNAMIC_DRAW );
    

If you are doing complex operations on geometries this works well. Understanding how the buffers are created and used by WebGLRenderer is important.

  • Nice and complete answer, seems to worth the bounty. – Sebastien Jul 12 '13 at 07:37
  • I'm not sure though i shouldn't do the hard work on arraybuffers directly and do the work of building a correct THREE.Geometry outside of the worker (from thoses arrays) – Sebastien Jul 12 '13 at 07:38
  • How does the `for (f in 0...obj_faces.length) {` exactly work? According to Google Chrome it's invalid syntax, what browsers had you in mind when writing the answer in 2013? – Ferrybig Nov 29 '17 at 12:02