6
$\begingroup$

I need to build terrain using one cube with dimensions 1x1x1, the coordinates are provided in a .txt file and there are about 11M triplets.

The problem is that using my current code I can only draw about 60k of them, then the browser tab is resetted and a prompt to stop an unresponsive script comes out, so I use too much memory and time to generate them.

Here is the chunk of code I use to draw them:

function generateCubes(data) {
    var cubeGeometry = new THREE.CubeGeometry(cubeSize, cubeSize, cubeSize);
    var material = new THREE.MeshLambertMaterial({color: 0x587058});
    var mesh = new THREE.Mesh(cubeGeometry, material);
    var mergedGeo = new THREE.Geometry();
    var instance;
    var line = data[0].split(';');
    var translateX = line[0], translateY = line[1], translateZ = line[2];
    //var group = new THREE.Object3d();
    for(var i = 0; i < 100000; i++) { // should go to data.length
        line = data[i].split(';');
        //instance = mesh.clone();
        //instance.position.set(line[0] - translateX, line[2] - translateZ, line[1] - translateY);
        //group.add(instance);
        mesh.position.x = Number(line[0]) - translateX;
        mesh.position.y = Math.round(Number(line[2]) - translateZ);
        mesh.position.z = Number(line[1]) - translateY;
        mesh.updateMatrix();
        mergedGeo.merge(instance.geometry, instance.matrix);
    }
    group = new THREE.Mesh(mergedGeo, material);
    scene.add(group);
}

The function is called from a success in an $.ajax call.

The commented parts are used without merged geometry, that way I can draw around 100k of the data.

$\endgroup$
1
  • 1
    $\begingroup$ You may have to use culling and only draw visible cubes if you can't do a million cubes. Another option is to merge cubes into larger rectangular shapes. $\endgroup$
    – Alan Wolfe
    Jan 5, 2016 at 1:16

1 Answer 1

2
$\begingroup$

As suggested in the comments, there's a few ways you might be able to reduce the geometry before merging it into the big mesh and sending it out for drawing.

  • First of all, you might not want to draw cubes that are hidden behind other cubes. While this is not a trivial thing to check, it becomes easier when we at least try to limit it to cubes that are on the outer surface of the terrain and the cubes are laid out in a regular grid. In this case you first of all make a regular grid storing a boolean flag for each coordinate where there's a cube. Then all you need to do is walk over that array and for each active cell check its neighbours' flags and only add it to the geometry when it doesn't have all 6 face-neighbours active too. You can even optimize this by checking only the 3 neighbours in the direction of the camera.

  • Another thing you can do is frustum culling, basically ignoring all cubes that are not inside the actual view volume, which amounts to just checking the cubes against the 6 planes of the viewing frustum.

  • What you also could do is perform basic backface culling yourself, and only adding the geometry of the 3 cube faces that actually face the camera (or better yet, combining it with the first point, the ones facing the camera and not having an active neighbour).

But all this only reduces the amount of geometry that you are generating and sending over for drawing. It does not do anything for reducing the actual computation you do to generate that geometry (rather on the contrary actually). It is not clear what exactly it is that's causing your script to take too long or acquire too many resources but I also don't know anything about Javascript or Ajax or whatever specific web-stuff you're doing.

  • Maybe it's possible to delegate all this to some kind of background task that doesn't block the main process. This way you might also be able to process the whole file in smaller batches, generating parts of the whole geometry and updating the display whenever you generated another batch.
  • The above method might help to reduce overall memory consumption if the amount of actually generated geometry is much less than those 11M cubes from the file and if the regular grid isn't too large either. But you actually only need 1 bit for every grid cell, making just 2MB for 256^3 grid and 128 MB for a 1024^3 grid. You might further reduce this by tiling the grid space into smaller sub grids and processing these each. However, this might require you to traverse the terrain file multiple times if that isn't already sorted appropriately.
  • Which brings us to the possibility of simply restructuring your input file format to better facilitate any of the above methods, like already sorting your cubes into spatial subgrids, or even storing a full boolean grid rather than a compact list of coordinates.

This all really depends on what the bottleneck is here. But it should give you some general ideas of how you could approach this for optimization.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.