2

Anyone know if it's possible to merge a set of cube geometries in a web worker and pass it back to the main thread? Was thinking this could reduce the lag when merging large amounts of cubes.

Does Three.JS work okay in a web worker, and if it does, would it be possible (and faster) to do this? Not sure if passing the geometry back would take just as long as merging it normally.

At the moment I'm using a timed for loop to reduce the lag:

// This array is populated by the server and contains the chunk position and data (which I do nothing with yet).
var sectionData = data.secData;

var section = 0;
var tick = function() {
    var start = new Date().getTime();
    for (; section < sectionData.length && (new Date().getTime()) - start < 1; section++) {
        var sectionXPos = sectionData[section][0] * 10;
        var sectionZPos = sectionData[section][1] * 10;
        var combinedGeometry = new THREE.Geometry();

        for (var layer = 0; layer < 1; layer++) { // Only 1 layer because of the lag...
            for (var x = 0; x < 10; x++) {
                for (var z = 0; z < 10; z++) {
                    blockMesh.position.set(x-4.5, layer-.5, z-4.5);
                    blockMesh.updateMatrix();
                    THREE.GeometryUtils.merge(combinedGeometry, blockMesh);
                }
            }
        }

        var sectionMesh = new THREE.Mesh(combinedGeometry, grassBlockMat);
        sectionMesh.position.set(sectionXPos, 0, sectionZPos);
        sectionMesh.matrixAutoUpdate = false;
        sectionMesh.updateMatrix();
        scene.add(sectionMesh);
    }
    if (section < sectionData.length) {
        setTimeout(tick, 25);
    }
};
setTimeout(tick, 25);

Using Three.JS rev59-dev.

Merged cubes make up the terrain in chunks, and at the moment (due to the lag) each chunk only has 1 layer.

Any tips would be appreciated! Thanks.

Joey Morani
  • 25,431
  • 32
  • 84
  • 131
  • 1
    Ok so I found out that merging geometry was sucking the life out of my program, taking up 33% CPU usage. All I really needed was updated verticies with the matrix applied, and managed to get this down to 4-7% by copying the merge method into my code and chopping all the parts I didn't need. Much less painful than using a web worker. – mattdlockyer Jun 18 '13 at 17:07
  • Thanks Matt! I'll give that a go before trying your answer below. Never occurred to me that merging might be doing other unneeded things. – Joey Morani Jun 18 '13 at 23:49
  • It most certainly is if all you need is to add more verticies with default normals, uvs, and other nonsense... In my case it was updating geometry so recreating the geometry array was even overkill. Worked for me to inline the parts I needed into my own update method and now it's flying... – mattdlockyer Jun 19 '13 at 18:19

1 Answers1

3

THREE.JS will not work in a web worker, however you can copy those parts of the library that you need to work both in the main thread and in your web worker.

Your first problem will be that you cannot send the geometry object itself back to the main thread.

Since the web worker onmessage variable passing works only by sending copies of JSON (not javascript objects) or references to ArrayBuffers, you would have to decode the geometry down to each float, pack it in an ArrayBuffer, and send a reference back to the main thread.

Note those are called transferable objects and once sent, they are cleared in the webworker / main thread from which they came.

See here for more details:

http://www.html5rocks.com/en/tutorials/workers/basics/

https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers

Here is an example of packing position vertices into an array for a physics type system:

//length * 3 axes * 4 bytes per vertex
var posBuffer = new Float32Array(new ArrayBuffer(len * 3 * 4));

//in a loop

//... do hard work

posBuffer[i * 3] = pos.x; //pos is a threejs vector
posBuffer[i * 3 + 1] = pos.y;
posBuffer[i * 3 + 2] = pos.z;

//after loop send buffer to main thread
self.postMessage({posBuffer:posBuffer}, [posBuffer.buffer]);

I copied the THREE.JS vector class inside my web worker and cut out all the methods I didn't need to keep it nice and lean.

FYI it's not slow and for something like n-body collisions it works well.

The main thread sends a command to the web worker telling it to run the update and then listens for the response. Kind of like a producer consumer model in regular threading.

mattdlockyer
  • 6,984
  • 4
  • 40
  • 44
  • 1
    threejs works in webworkers now. They removed all of the references to the window object. – Spencer Oct 18 '15 at 05:34
  • 1
    Ah sorry you're right. I kept running into issues trying to send back geometries. I could send points (Vector2), though. Not sure what is up with that, but parsing JSON in a web worker to grab the point data and send it back did improve load time quite a bit, around double. I wish I could send back geometries though! – Spencer Oct 18 '15 at 06:46