saward
saward

Reputation: 439

Three.js raycaster intersection empty when objects not part of scene

I've tried improving rendering time on my project by creating meshes and putting them as part of a larger geometry, and having just that single geometry as the object I add to the scene. I thought that I would still be able to manage picking of objects by having an array of the original meshes, and pass those to the raycaster. I used the following code:

var vector = new THREE.Vector3( ( loc_x / window.innerWidth ) * 2 - 1, - ( loc_y / window.innerHeight ) * 2 + 1, 0.5 );
projector.unprojectVector(vector, camera);
var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
var objects = [];

var i = active_regions.length;
while (i--) {
  objects = objects.concat(active_regions[i].mesh_entities);
}
var intersects = raycaster.intersectObjects( objects );
if ( intersects.length > 0 ) {
  console.log("Intersection: " + intersects);
}

So in the above code, active_regions contains the original individual meshes, and I create an array on the fly to specify which objects I want to select from. Unfortunately intersects comes up empty.

If I modify my project slightly so that I have all those mesh_entities added to the scene individually, then the above code works and I can successfully select objects. Unfortunately, the whole scene then renders slowly.

What's a good way (or some good ways) for me to successfully check for intersection with the ray, without slowing down my rendering?

Thanks!

Upvotes: 2

Views: 3213

Answers (3)

Ben Adams
Ben Adams

Reputation: 3441

You need to update the Matrices for the objects not in the render scene manually as its done as part of the render process so if you are using your ghost scene, you don't need to render it, just update the matrices before doing the intersection:

scene_ghost.updateMatrixWorld(true);

Upvotes: 7

sharpper
sharpper

Reputation: 3005

I am doing something similar in this and have verified that you need to render the scene to do proper raycasting. It is easy to optimize this however to just render both screens and have one clear over the other. You should be able to change your code to this, granted the second render call will clear over the first screen:

function render() {
  renderer.render( scene_ghost, camera );
  renderer.render( scene, camera );
}

Upvotes: 0

saward
saward

Reputation: 439

I solved this by having a ghost scene. Essentially, I added all objects to the ghost scene as their individual meshes, and then when I use raycaster it works.

However, I had to use functions along these lines:

function flip_render_ghost(yes) {
  if (yes == true) {
    scene_ghost.add(camera);
    render_ghost = true;
  } else {
    scene.add(camera);
    render_ghost = false;
  }
  render();
}

function render() {

  if (render_ghost == true) {
    renderer.render( scene_ghost, camera );
  } else {
    renderer.render( scene, camera );
  }

}

Whenever I am about to check for collisions, I flip to rendering ghost scene, check for hits, then flip back to normal rendering.

Edit: I have since discovered that objects cannot belong to multiple scenes (though geometries can be shared). So what I have done is created simple meshes for the picking scene. This requires more memory, but gives the option of having a simpler mesh to use for selection for faster picking. Also, it seemed to work for me to send the children of the ghost scene itself to the raycaster. You may need to, like me, add a property to each object in the ghost scene that references the main object you are trying to pick.

Upvotes: 1

Related Questions