Threejs - How to select all objects in an area?

I am using Three.js and I am wondering how to get all the objects in a given area?

For example, get all the objects found in the green square: Mass object selection

Decision:

        getEntitiesInSelection: function(x, z, width, height, inGroup) {
            var self = this,
                entitiesMap = [],
                color = 0,
                colors = [],
                ids = [],
                pickingGeometry = new THREE.Geometry(),
                pickingMaterial = new THREE.MeshBasicMaterial( { vertexColors: THREE.VertexColors } ),
                pickingScene = new THREE.Scene(),
                pickingTexture = new THREE.WebGLRenderTarget( this._renderer.domElement.width, this._renderer.domElement.height),
                cloneMesh,
                entities = inGroup ?
                    engine.getObjectsByGroup(inGroup) : engine.getRegisteredEntities();

            pickingTexture.generateMipmaps = false;

            //Go over each entity, change its color into its ID
            _.forEach(entities, function(entity) {
                if(undefined == entity.threeRenderable) {
                    return ;
                }

                //Clone entity
                cloneMesh = entity.threeRenderable.mesh().clone();
                cloneMesh.material = entity.threeRenderable.mesh().material.clone();
                cloneMesh.material.map = null;
                cloneMesh.material.vertexColors = THREE.VertexColors;
                cloneMesh.geometry = entity.threeRenderable.mesh().geometry.clone();
                cloneMesh.position.copy( entity.threeRenderable.mesh().position );
                cloneMesh.rotation.copy( entity.threeRenderable.mesh().rotation );
                cloneMesh.scale.copy( entity.threeRenderable.mesh().scale );

                //Cancel shadow
                cloneMesh.castShadow = false;
                cloneMesh.receiveShadow  = false;

                //Set color as entity ID
                entitiesMap[color] = entity.id();
                self._applyVertexColors(cloneMesh.geometry, new THREE.Color( color ) );
                color++;

                THREE.GeometryUtils.merge( pickingGeometry,  cloneMesh);
            });

            pickingScene.add( new THREE.Mesh( pickingGeometry, pickingMaterial ) );

            //render the picking scene off-screen
            this._renderer.render(pickingScene, this._objs[this._mainCamera], pickingTexture );
            var gl = this._renderer.getContext();

            //read the pixel under the mouse from the texture
            var pixelBuffer = new Uint8Array( 4 * width * height );
            gl.readPixels( x, this._renderer.domElement.height - z, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixelBuffer );

            //Convert RGB in the selected area back to color
            for(var i=0; i<pixelBuffer.length; i+=4) {
                if( 0 == pixelBuffer[i] && 0 == pixelBuffer[i+1] && 0 == pixelBuffer[i+2] && 0 == pixelBuffer[i+3] ) {
                    continue;
                }

                color = ( pixelBuffer[i] << 16 ) | ( pixelBuffer[i+1] << 8 ) | ( pixelBuffer[i+2] );
                colors.push(color);
            }
            colors = _.unique(colors);

            //Convert colors to ids
            _.forEach(colors, function(color) {
                ids.push(entitiesMap[color]);
            });

            return ids;
        }

The line engine.getObjectsByGroup(inGroup) : engine.getRegisteredEntities(); simply returns an array of entities, which, in turn, iterate over the entities:

 _.forEach(entities, function(entity) { ...

Only objects with the "threeRenderable" property (object) are visible, so I ignore those who do not:

if(undefined == entity.threeRenderable) {
      return ;
}

then I will merge the cloned mesh object using the pickingGeometry method:

THREE.GeometryUtils.merge( pickingGeometry, cloneMesh);

In the end, I add the geometry assembly to the Scene set:

 pickingScene.add( new THREE.Mesh( pickingGeometry, pickingMaterial ) );

Then I read the colors of the selected area and return an array of identifiers.

You can check out the Node.js game engine . Then I wrote.

+1
source share
1

- , - , , , - IMO, , - .

, 2 raycasts, , , , , .

:

   function onDocumentMouseDown(event) {
      // usual Raycaster stuff ...

      // get the ground intersection
      var intersects = raycaster.intersectObject(ground);

      GlobalGroundSelection = {
        screen: { x: event.clientX, y: event.clientY },
        ground: intersects[0].point
      };
    }

   function onDocumentMouseUp(event) {
      // ends a ground selection
      if (GlobalGroundSelection) {
        // usual Raycaster stuff ...

        // get the ground intersection
        var intersects = raycaster.intersectObjects(ground);

        var selection = {
          begins: GlobalGroundSelection.ground,
          ends: intersects[0].point
        };

        GlobalGroundSelection = null;
        selectCharactersInZone(selection.begins, selection.ends);
      }
    }

    function onDocumentMouseMove(event) {

      if (GlobalGroundSelection) {
        // in a selection, draw a rectangle
        var p1 = GlobalGroundSelection.screen,
            p2 = { x: event.clientX, y: event.clientY };

        /* with these coordinates
          left: p1.x > p2.x ? p2.x : p1.x,
          top: p1.y > p2.y ? p2.y : p1.y,
          width: Math.abs(p1.x - p2.x),
          height: Math.abs(p1.y - p2.y)
        */
      }
    }

select:

function selectCharactersInZone (start, end) {

  var selected = _.filter( SELECTABLE_OBJECTS , function(object) {
    // warning: this ignore the Y elevation value
    var itsin = object.position.x > start.x
            && object.position.z > start.z 
            && object.position.x < end.x
            && object.position.z < end.z;

    return itsin;
  });

  return selected;
}

: , , Y-, .

My 2c

+1

All Articles