Closest face to mouse

I realized selection of faces by raycasting. But customer want selection of faces if mouse is around the face (for example where are red arrows in the pic). In this case I can not use raycasting or have to build additional geometries around the faces, but I think it will be too costly
How it can be solved?



This is a project, where I realise this feature (quick assembling)

Have you considered to just clone the mesh, scale it and then use it not for rendering but just for raycasting? At least the raycasting performance should not be worse in this case.

Although scaling might not always produce good results depending on your geometry, it’s an approach that should be easy to implement. I would start with that and see how good it goes.

1 Like

We cannot just scale object, because, as you can see in the video, there are grooves, which we select too, and if we scale object grooves will move to another place.

If you always have some mesh a ray can collide with (like ground, which you seem to have):

  1. Create a collision box (Cube or Box3 with size that will determine your selection radius.)
  2. Ray-cast mouse location on the scene and move the collision box to where the collision happens.
  3. Check which models’ bounding boxes collide with the collision box.
  4. For each colliding model detect which faces overlap with the collision box (intersectsTriangle may also help), ignore faces which point in the opposite direction.

Otherwise, if you don’t have a ground mesh, and I understood correctly, you can’t really do what you are trying to do, since cursor has no depth - some faces that are visually next to the cursor in 2D can be far apart in 3D. One more thing you could do it cast more rays with some offset - create a Vector2 with (mouse.x + offset , mouse.y), duplicate it 8 times and rotate around the origin by 45°. Additional rays will then pick up objects that are nearby the mouse position, with some precision. If performance gets hit - you can do the collision testing on an offscreen canvas worker and return only the collisions to the main thread.

1 Like

About collision box is a good idea, only I will place it to intersection with plane, which I will put along object in it centre

Upd. but this does not solve the problem if we look at the object from the end

Upd2. I’ll create a bounding box a little bit larger than object and raycast it. In intersection I’ll put cube and will find intersections cube with faces

I took advice from @Mugen87 and combined it with advice from @mjurczyk.
This is solution

function findClosestFace( object ) {

	let closestPlane = { face: null };

	let closestPlanes = [];

	let minDistance = Infinity;

		object.userData.triangles.map( item => {

			object.attach( planeSnapBox );

			var box = planeSnapBox.geometry.boundingBox.clone();
			box.applyMatrix4(planeSnapBox.matrixWorld);

			if ( box.intersectsTriangle( item.triangleWorldCoords ) ){

				closestPlanes.push( item );

			}

			scene.attach( planeSnapBox );

		})

		if ( closestPlanes.length === 0 ){

			console.log( 'Cube not intersect')
			
			 closestPlane.face = null;
			 return closestPlane;
		}


	closestPlanes.map( item => {

		let point = new THREE.Vector3();

		let cursor = planeSnapBox.position.clone();
		object.worldToLocal( cursor );

		item.triangleWorldCoords.closestPointToPoint( cursor, point);
		
		let distance = point.distanceTo( cursor );

		if ( distance < minDistance ){
			
			minDistance = distance;

			closestPlane.face = item.face;
			closestPlane.triangle= item.triangleWorldCoords;

		}


	})

	return closestPlane;

}
1 Like