Raycast Collision problem

Hi,

I do have a 3D Model which has a root-node containing 2 meshes (lets consider it a 2 sphere meshes, one in bigger size and one in smaller size). When visualizing you can see smaller sphere mesh ( 2nd sphere mesh) will be inside a bigger sphere mesh(1st sphere mesh). When performing ray-cast, the ray-cast must collide only on the 1st mesh and not on the inner mesh. But when i zoom inside and perform a ray-cast on the 2nd sphere the name of the 2nd sphere mesh must be taken into account. But, I am able to see both the names when debugging. The raycast penetrates through the 1st sphere and hits 2nd sphere. I would like to avoid raycast penetration.

      function raycast ( e ) {

                mouse.x = ( e.touches[0].pageX / window.innerWidth ) * 2 - 1;

                mouse.y = - ( e.touches[0].pageY / window.innerHeight ) * 2 + 1;

                raycaster.setFromCamera( mouse, camera );    

                var intersects = raycaster.intersectObjects( scene.children,true);

                for ( var i = 0; i < intersects.length; i++ ) {
     
                    if(intersects[i].object.name =="1st sphere name"){

                               console.log(intersects[i].object.name);
                        }
                      if(intersects[i].object.name =="2st sphere name"){

                               console.log(intersects[i].object.name);
                        }
                    }

                }

            }

Are you rendering your spheres with a double sided material?

1 Like

Sharing the 3D Model, You can see a lighthouse and a plane. The plane (referred smaller sphere) is a child of the lighthouse object (referred bigger Sphere). demo.glb (931.9 KB) When I peform raycast at a approx. position where the plane is present, the ray penetrates and hits the plane too. How to avoid this.

Okay, I’m answering my question by myself: Yes, the lighthouse/sphere uses a double sided material. Try to use a material which only renders the front side.

1 Like

Sorry, I was not sure what is double sided material, came to know about it after googling. It is working, I enabled backface culling in blender and exported it. But if I try positioning the plane/smaller sphere (the side where material is applied) normal to the raycast , it is still penetrating the lighthouse/bigger sphere and hitting the plane/smaller sphere.

Can you please explain in more detail how this setup looks like?

Hi,
Uploading the files after a long time. The model contains a Gazebo (parent) and a plane (child) demo.glb (2.9 MB) uploadhtmlfile.html (4.0 KB) . Raycast is called on a mouse click, and when the ray hits on the mesh named “Plane” I perform console.log(“Clicked on Plane”); The issue is that raycast is not colliding with the outer mesh and penetrates and hits the “Plane”. How to avoid this problem? Instead the ray has to collide with the inner “Plane” mesh only when zoomed in and clicked on it.

@Mugen87 I’m the newest guy so if I’m wrong I authorize you to slap me …really (you are a master for me)

But if I remember correctly raycast collect in array every objects intersected from camera to screen coords direction, sorted from camera distance.
If J_V problem is to receive only the first one he could try to ask only for it?
with

intersects[0]
1 Like

@alessandro_guarino

that is a working for now ! as you said [raycast collect in array every objects intersected from camera to screen coords direction, sorted from camera distance.]. But is there any other way to restrict the ray from penetrating into the mesh , instead the ray should be able to hit only the gazebo mesh?

No way to restrict the ray penetration (or I don’t know how) but, in my opinion, you don’t need to restrict.
In your code, if the ray intersects two objects, your cycle is called twice and it’s ok
you have two console.log because you check both.

if you want to do something only when a specific object is intersected (eg “1st sphere name”) you can check only “1st sphere name” …I suppose, but I don’t know your final goal

for ( var i = 0; i < intersects.length; i++ ) {
     
                    if(intersects[i].object.name =="1st sphere name"){

                               console.log(intersects[i].object.name);
                        }
                      //if(intersects[i].object.name =="2st sphere name"){

                               //console.log(intersects[i].object.name);
                        //}
                    }

I forgot
if you need consol.log only when your sphere is the first object it’s easyest
you don’t need the for cycle


     
                    if(intersects[0].object.name =="1st sphere name"){

                               console.log(intersects[0].object.name);
                        }

1 Like

You can specify the objects to be checked.
Just extended my beginner example with raycast.

* discourse.threejs.hofk.de => BeginnerExample

// ... step 10: raycaster 
//=================================================================================================
			// https://threejs.org/docs/index.html#api/en/core/Raycaster
const raycaster = new THREE.Raycaster( ); // see function raycasting( ); in animate
const mouse = new THREE.Vector2( ); // see function onWindowMousemove( event )
let intersects = []; // array of intersected objects
			// https://threejs.org/docs/index.html#api/en/geometries/OctahedronGeometry			
const ohGeometry = new THREE.OctahedronGeometry( 0.3 );
const ohMesh = new THREE.Mesh( ohGeometry, new THREE.MeshPhongMaterial( { color: 0xff0045 } ) );
scene.add( ohMesh );
const objs = [ ohMesh, flowerMesh, ballMesh, diceMesh, sandPileMesh, rampMesh, stemMesh, flagpoleMesh, flagMesh, sfSprite, sheetMesh ];
const infos = [ 'octahedron', 'flower', 'ball', 'dice', 'sand', 'ramp', 'stem', 'pole', 'three.js', 'sunflower', 'sheet' ]	 
let index = 0;
objs.forEach( obj => { obj.name = infos[ index ]; index++; } );  // names for some objects

// ======= to step 10 ============

function raycasting( ) {
	
	if( range.value > 9.5 && range.value < 10.5  ) { // only step 10 
	
		raycaster.setFromCamera( mouse, camera );
		intersects = raycaster.intersectObjects( objs ); // objs - objects to raycast
		
		if ( intersects.length > 0 ) { // hit
			
			info.style.fontSize = '5vh';
			info.style.color = 'white';
			info.innerHTML = ' you got a hit => ' + intersects[ 0 ].object.name; //  ...[ 0 ]  first intersected object
			ohMesh.material.color.setHex( 0x4500ff );
			
		} else {
		
			info.style.fontSize = '1.9vh';
			info.style.color = 'black';
			info.innerHTML = 'Beginner Example';
			ohMesh.material.color.setHex( 0xff0045 );
			
		}
		
	}
	
}
2 Likes

Yes, this is possible via Raycaster.layers.

2 Likes

Thanks @Mugen87 @alessandro_guarino @hofk . I was able to figure it out with all the help.

2 Likes