mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
102k stars 35.33k forks source link

Picking and a large terrain mesh. #2155

Closed hsmanfroi closed 12 years ago

hsmanfroi commented 12 years ago

I don't know if this is the best place for this - if someone can point me to a forum where we can discuss three.js implementations, please reply.

I was building a terrain made of 16x16 1-plane geometries (tiles). I implemented picking using ray, projector, intersectsRecursive. Picking worked great! but performance was bad when I grew the terrain to 64x64 tiles.

I used THREE.GeometryUtils.merge to merge all my 1-plane geometries in one large terrain mesh. Performance is great! Picking does not work properly anymore. It looks like it works in the lower half of the screen.

My questions:

Any help appreciated. : )

Code:

Picking:

    function mousedown(event) {

        if(!_this.enabled) return;

        event.preventDefault();
        event.stopPropagation();

        // get mouse coor in [ -1, 1 ] within rendering canvas
        var mouse = new THREE.Vector2(
             (event.clientX / _this.domElement.offsetWidth  ) * 2 - 1, 
            -(event.clientY / _this.domElement.offsetHeight ) * 2 + 1);

        var projector = new THREE.Projector();
        var ray = projector.pickingRay(mouse, _this.camera);
        var objects = [];

        intersectsRecursive(ray, _this.scene.children, objects);
        objects.sort(function (a, b) {return a.distance - b.distance;});

        if(objects.length) 
        {
            _this.picked = objects[0];
            _this.dispatchEvent(pickedEvent);
        }
    };

    function intersectsRecursive(ray, objects, outIntersected) {

        for ( var i = 0, l = objects.length; i < l; i ++ ) {

            if(objects[i].pickable)
                Array.prototype.push.apply(outIntersected, ray.intersectObject(objects[i])); 

            intersectsRecursive(ray, objects[i].children, outIntersected);
        }
    }

Generating terrain chunks (now, one big merged chunk)

            for(x = 0; x < 64 - 1; x++) {
                for (y = 0; y < 64 - 1; y++) {

                    chunk = new TerrainChunk([
                        terrain.heightData[(x) * dimension + (y)] * terrain.maxHeight,
                        terrain.heightData[(x) * dimension + (y + 1)] * terrain.maxHeight,
                        terrain.heightData[(x + 1) * dimension + (y)] * terrain.maxHeight,
                        terrain.heightData[(x + 1) * dimension + (y + 1)] * terrain.maxHeight
                    ]);

                    chunk.position.x = x;
                    chunk.position.z = y;

                    //terrain.add(chunk);

                    if(mergedGeometry === null) {

                        mergedGeometry = chunk.geometry;
                        console.log(mergedGeometry);
                    }
                    else {

                        console.log("merge : " + chunk);
                        THREE.GeometryUtils.merge(mergedGeometry, chunk);
                    }
                }
            }

            var mergedMesh = new THREE.Mesh(mergedGeometry, TerrainChunk.BaseMaterial);

            mergedMesh.pickable = true;

            terrain.add(mergedMesh);
hsmanfroi commented 12 years ago

Oh well. This is specially confusing because, testing the heightmap out, I made it work.

My heightmap values were ranging from 0 - 1, and being multiplied by the maxHeight (64). Picking did not work on the merged terrain.

I changed the heightmap values to range from 1 - 2, still being multiplied by the maxHeight (64). Picking works all through the merged terrain.

I must imagine this is some detail in the ray picking. I have no idea though.

Still, my questions stand: what is the most performance-assured way of handling a large (4096x4096) terrain? Each tile is around ~1m large. The camera is fixed and almost isometric (think SimCity, or Warcraft3).

I am thinking about chopping a large heightmap into smaller chunks (16x16 probably) and loading them one at a time as chunks, adding and removing them from the Three.js scene based on distance to player.

I'll try and put this test up online so you can understand better once I get home from work.

hsmanfroi commented 12 years ago

I fixed this, though very unfortunately I still cannot know why I had problems in the first place. :(