diarmuid
diarmuid

Reputation: 343

Raycaster.intersectObjects() not returning anything?

I set up my scene as follows:

document.addEventListener('mousedown', onDocumentMouseDown, false);

var container = document.getElementById("myCanvas");

scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth*0.99, window.innerHeight*0.99 );
container.appendChild( renderer.domElement );

room_material = new THREE.MeshBasicMaterial({color: 0x00ff00});
room_material.side = THREE.DoubleSide;

objects = [];

camera.position.z = 19;
camera.position.x = 5;
camera.position.y = 30;

I have an array of objects that i'm trying to detect if a click intersects with them, defined as follows:

var thing0 = new THREE.Shape();
thing0.moveTo(-12.1321728566, 35.3935535858);
thing0.lineTo(7.10021556487,35.3935535858);
thing0.lineTo(7.10021556487,19.7039735578);
thing0.lineTo(5.12636517425,19.7166264449);
thing0.lineTo(5.12636517425,33.6221493891);
thing0.lineTo(-12.1377356984,33.6439534769);
var thing0Geom = new THREE.ShapeGeometry(thing0);
var thing0Mesh = new THREE.Mesh( thing0Geom, room_material );
thing0Mesh.name = "abcd";
scene.add(thing0Mesh);
objects.push(thing0Mesh);

I then render the scene with the following code:

renderer.render(scene, camera);
requestAnimationFrame(render);

And lastly I use the following code for the mouse click event:

function onDocumentMouseDown(event) {
    var vector = new THREE.Vector3(( event.clientX / window.innerWidth ) * 2 - 1, -( event.clientY / window.innerHeight ) * 2 + 1, 0.5);
    vector = vector.unproject(camera);
    var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
    var intersects = raycaster.intersectObjects(objects, true);
    alert("well, you clicked!");
    if (intersects.length > 0) {
        alert("wow, it worked");
    }
}

However, no matter what I do the alert never gets called when it follows raycaster.intersectObjects(objects, true); However it does get called when it is placed anywhere before it. It seems that raycaster.intersectObjects(objects, true); is a bit of a black hole in this case?

I assume I simply have something wrong in my setup? Any help would be appreciated!

Upvotes: 2

Views: 7806

Answers (3)

adeler
adeler

Reputation: 151

There are two things I tried that worked:

1) Make sure you're using Three.DoubleSide if your mesh face is not pointing towards origin of the ray. This is directly from the documentation:

"Note that for meshes, faces must be pointed towards the origin of the ray in order to be detected; intersections of the ray passing through the back of a face will not be detected. To raycast against both faces of an object, you'll want to set the material's side property to THREE.DoubleSide."

2) Use mesh.updateMatrixWorld() prior to raycasting. This comes from another stackoverflow post: threejs raycasting does not work

mesh.updateMatrixWorld(); // add this

raycaster.set(from, direction);

Upvotes: 10

davidchappy
davidchappy

Reputation: 301

This is an old question, but I was running into a similar issue and thought what I learned might help someone else. My code setup is very similar to JohnnyDevNull's, so I won't repeat it.

The Problem

In my case, calling intersectObjects with scene.children doesn't work because it picks up other objects like ambientLighting, etc. I believe this is what the OP mentions in his own answer.

My Solution

The function below takes an empty array (intersects). It searches each child in scene for THREE Group objects and Mesh objects and adds Mesh objects to the array. For Groups, it sets recursive to true, which applies .intersectObject to each child. Once the array is built up, it calls your supplied callback function on the array.

function raycastMeshes(intersects, callback, theScene, theRaycaster) {
  var scene = theScene || scene || new THREE.Scene();
  var raycaster = theRaycaster || raycaster || new THREE.Raycaster();

  for (var i in scene.children) {
    if (scene.children[i] instanceof THREE.Group) {
      intersects = raycaster.intersectObjects(scene.children[i].children, true);
    } else if (scene.children[i] instanceof THREE.Mesh) {
      intersects.push(raycaster.intersectObject(scene.children[i]));
    }
  }

  if (intersects.length > 0) {
    return callback(intersects);
  } else {
    return null;
  }
}

Adapting to your Use Case

This is obviously a fairly naive and specific use case, but should serve as a launching board for you if you're having a similar problem.

Upvotes: 1

JohnnyDevNull
JohnnyDevNull

Reputation: 982

I think i have found the problem. I have to add the meshes to an extra array. An intersectObjects over the scene.children don't work, because there are other objects in there with the meshes.

So when i give the intersectObjects( mesh[] ) an mesh array than it works.

For more code detail see https://github.com/mrdoob/three.js/issues/8081

Upvotes: 4

Related Questions