Detect intersection with scene.children

Hi, so, Im currently trying to make a shooter game on my own, just to simply expand my knowledge, anyway, Im trying to somewhat understand the concept of Raycaster. Lets say I have a bullet, once the bullet hits an object (gets to an intersection), it will let me know, currently, this is how my code looks:
(Before animate)
const ray = new THREE.Raycaster();
(Animate)

			const speedFactor = -10;
			bullets.forEach(b => {
				ray.ray.origin.copy(b.position);
				const inters = ray.intersectObjects(scene.children);
				if(inters.length > 0) {
					$(".debug").html("hit");
				}
				b.getWorldDirection(direction);
				b.position.add(direction.multiplyScalar(speedFactor));
			});

I had some previous attempts, but I never got to actually seeing yes on my screen, so, what could be possibly wrong?

Do you set the direction of the raycaster?

ray.ray.set(origin, direction)

There are other properties like near and far you can try.

Also if you have objs that are grouped, you can try to use ray.intersectObjects(scene.children, true) The second param will search recursively through the group of objs

Well, I tried that, but it still does not work…

Draw a arrow along your raycaster direction to see if its right
And console.log your intersects

Or make a live demo, for me, your code is not enough to help

Take a look at my example:

Use green arrow and aim whatever object you wish.
when raycaster detects object the object will change color

I dont know if this is correct way to do intersection but for my case it helped me .

function castRay(){
requestAnimationFrame( castRay );

			dir = camera.getWorldDirection( directionVector );
			pos = camera.getWorldPosition( positionVector);	

			var raycaster = new THREE.Raycaster( pos, dir.normalize() );	
			var intersects = raycaster.intersectObjects( scene.children );

			if( intersects.length>0 ){
				itr++;
				opacity += (1-0.6)/100;
				center.style.opacity = 0.6 + opacity;
				if( itr > 30 ){
					intersects[0].object.material.color.set( 0xff0000 );
					intersects[0].object.material.color.getHSL( colorHSL )
					alpha += 0.01;
					l = Math.abs( Math.cos( alpha ));
					intersects[0].object.material.color.setHSL( colorHSL.h, colorHSL.s, l );
					waiting = false;
				}
			}		
			else if( !waiting ){
				itr = 0;
				opacity = 0;
				center.style.opacity = 0.6;

				for( var i=0; i<arr.length; i++){
					arr[i].material.color.set( 0xaaafff);
				}	
				waiting = true;
			}	
		}

		castRay();
  1. Use world position instead of position (if your bullet is within any kind of container, position becomes a local transform):
  2. If your scene contains grouped objects / objects with submeshes, enable recursive intersections when raycasting.
  3. In real-life situation, you probably don’t want to intersect the entire scene - limit testing to only the objects that care about bullets hitting them.
  4. You don’t have to modify origin directly - using Raycaster.set lets you override both origin and direction.
const position = new Three.Vector3();
const direction = new Three.Vector3();
const raycaster = new Three.Raycaster(new Three.Vector3(), new Three.Vector3(), 0.0, 100.0);

const speedFactor = 10.0;

bullets.forEach(bullet => {
  bullet.getWorldPosition(position);
  bullet.getWorldDirection(direction);

  raycaster.set(position, direction);
  
  const hits = raycaster.intersectObjects(scene.children, true);

  if (hits[0]) {
    // Hit
  }

  bullet.position.add(direction.multiplyScalar(speedFactor).negate());
  direction.normalize();
});

Hi! The code works perfectly! But for some reason, even when I shoot just into the air (where no object children is) it says hit. I switched from scene.children to map.children but this still ocurs, Ill is there any workaround?

Isn’t by any chance bullet also a part of scene / map.children? In this case raycaster is probably colliding with the bullet itself. You can try offsetting the ray a little to the front (if it’s still colliding, offset it a bit more - it depends on the size of the model):

const position = new Three.Vector3();
const direction = new Three.Vector3();
const raycaster = new Three.Raycaster(new Three.Vector3(), new Three.Vector3(), 0.0, 100.0);

const speedFactor = 10.0;

bullets.forEach(bullet => {
  bullet.getWorldPosition(position);
  bullet.getWorldDirection(direction);

  raycaster.set(
    position.add(direction.clone().multiplyScalar(2.0), // <- offset ray to start a little in-front of the bullet
    direction
  );
  
  const hits = raycaster.intersectObjects(scene.children, true);

  if (hits[0]) {
    // Hit
  }

  bullet.position.add(direction.multiplyScalar(speedFactor).negate());
  direction.normalize();
});

That’s why it’s a good idea to store a list of “shootable” objects in a separate array - an test only against them (since you don’t really want bullets to collide with themselves or each other - that’s just poor player experience.)

1 Like