Jothi Kannan
Jothi Kannan

Reputation: 3358

three.js can't select the objects with Raycaster

I am having the following function to get the selected object, so my function is here

function onMouseDown(event) {
    console.log(event);
    event.preventDefault();

    mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
    // find intersections

    var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
    projector.unprojectVector( vector, camera );


    var pLocal = new THREE.Vector3(0, 0, -1);
    var pWorld = pLocal.applyMatrix4(camera.matrixWorld);
    var ray = new THREE.Raycaster(pWorld, vector.sub(pWorld).normalize());




    ray.set( camera.position, vector.sub( camera.position ).normalize() );
    var intersects = ray.intersectObjects( scene.children );
    //console.log(intersects);
    console.log(scene.children);
    if ( intersects.length > 0 ) {

    var clickedObject = intersects[0].object;

    console.log('objects '+intersects[ 0 ].object);
    console.log('objects id'+intersects[ 0 ].object.id);
    console.log('objects name'+intersects[ 0 ].object.name);

    if ( INTERSECTED != intersects[ 0 ].object ) {

    if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );

    INTERSECTED = intersects[ 0 ].object;
    console.log('INTERSECTED '+INTERSECTED);
    INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
    INTERSECTED.material.emissive.setHex( 0xff0000 );

    }

    } else {

    if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );

    INTERSECTED = null;

    }
}

but am getting empty array on intersects , i tried my level best but i can't find any solution here, if i console the scene.children i can see all the attached objects of the scene on before this am adding the object into scene as like here

var   loader = new THREE.JSONLoader();      
loader.load("uploads/accessories/3d/code/3dfile_"+file+".js",
      function(geometry, object_material) 
      {

          var object = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(object_material));
          model = new THREE.Object3D();
          model.id="Myid"+file;
          model.name="Myname"+file;
          model.userData ={ URL: "http://myurl.com" };
          model.add(object);    
          model.position.set(x,y,z);        
          model.scale.set(obj_width,obj_height,obj_rotation);   
          model.opacity =2;
          model.rotation.y = 600; 
          model.duration = 12000;
          model.mirroredLoop = true;
          model.castShadow = true;
          model.receiveShadow = true;

          console.log(model);   
          var smodel=model;
          scene.add(smodel);                            
      }
  );

now i want to get the added model by new THREE.Object3D(); in onMouseDown but i can't, any one have the same issue ?

Upvotes: 2

Views: 5190

Answers (4)

Hitesh Sahu
Hitesh Sahu

Reputation: 45120

Raycaster is little bit tricky I have added explanation

A typical setup need to be done for raycaster to work as follows:

first initialize a variable to hold mouse position from which we need to emit a ray

var mouse = {
  x: 0,
  y: 0
};

 //object intersected 
var INTERSECTED;

// pool of objects which can be selected
var objects = [];

// ray caster initialization
var  raycaster = new THREE.Raycaster();

We need to create a Object3D parent to hold all child meshes

let mainGroup = new THREE.Object3D();
// add into object pool
objects.push(mainGroup);
scene.add(mainGroup);


// add mesh to be select by ray caster in Object3D parent
mainGroup.add(meshToSelect);

Add an event listener to get mouse X,Y position

document.addEventListener("mousemove", this.onDocumentMouseMove, false);


  onDocumentMouseMove = event => {
    event.preventDefault();

    if (event && typeof event !== undefined) {
      mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
      mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    }
  };

Now use raycaster like this:

  renderScene = () => {

    // Emit ray
    raycaster.setFromCamera(mouse, this.camera);

    // all intersects 
    var intersects = raycaster.intersectObjects(objects, true);

    if (intersects.length > 0) {
      if (INTERSECTED != intersects[0].object) {
         //if new item selected swap color of new item 
         //& revert color of previous item
        if (INTERSECTED)
          INTERSECTED.material.color.setHex(INTERSECTED.currentHex);
        INTERSECTED = intersects[0].object;
        INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
        INTERSECTED.material.color.setHex(0xff0000);

      }
    } else {
       // None selected then revert color of previous item
      if (INTERSECTED)
        INTERSECTED.material.color.setHex(INTERSECTED.currentHex);
      INTERSECTED = null;
    }

    if (this.renderer) this.renderer.render(scene, this.camera);
  };

Upvotes: 1

gevaraweb
gevaraweb

Reputation: 923

Try to make through this example. Look at messages in the console.

<script src="js/controls/EventsControls.js"></script>

EventsControls = new EventsControls( camera, renderer.domElement );
EventsControls.draggable = false;

EventsControls.onclick = function() {

   console.log( this.focused.name );

}

var jsonLoader = new THREE.JSONLoader();
jsonLoader.load( "models/Tux.js", addModelToScene ); 


function addModelToScene( geometry, materials ) {

   var material = new THREE.MeshFaceMaterial( materials );
   model = new THREE.Mesh( geometry, material );
   model.scale.set( 10, 10, 10 ); model.name = 'Tux';
   model.rotation.x = -Math.PI/2; 
   model.position.set( 175, 45, 125 );
   scene.add( model ); 
   EventsControls.attach( model );

}

Upvotes: -2

Endorox
Endorox

Reputation: 99

You are using a MeshFaceMaterial which doesn't have a hex to grab. You have to get the 'materials array' from the 'material' like so:

for(var p =0; p < INTERSECTED.material.materials.length; p++){
    INTERSECTED.currentHex = INTERSECTED.material.materials[p].emissive.getHex();
}

This way you are not selecting the MeshFaceMaterial but the MeshLambertMaterial or MeshBasicMaterial that you are using for each face. If you are using images as your textures I would suggest checking out Three.js material texture and color for a quick answer to that question.

Hope this was helpful!

Upvotes: 1

WestLangley
WestLangley

Reputation: 104833

You need to pass in the recursive flag to Raycaster.intersectObjects().

intersects = ray.intersectObjects( scene.children, true );

Also, do not overwrite Object3D.id. Set Object3D.userData.id instead.

three.js r.68

Upvotes: 6

Related Questions