Raycaster: how to get the hit when clicking in proximity to an object?

I used to set the deprecated property “linePrecision” so that the intersectObjects(scene.children, true ) easily returns some line objects even if the mouse didn’t hit them exactly.

Now, I have some long thin CylinderBufferGeometry objects merged into a single geometry, then create a mesh on it. It looks like many lines.

When the mouse hits one of those “lines” exactly, the intersectObjects() does return a non-empty list. But, when the mouse slightly misses the target, the returned list will have 0 object in it.

I thought the Raycaster.params.Mesh.threshold would help, but whatever value I set didn’t make any difference.

Please advise me of how to lower the intersecting precision, in other words, how to get some intersected objects even if the mouse clicking position is far away from them.

create 2nd larger geometry, and do the raycast on that instead

That sounds like a clever trick, but I still expect the correct way to achieve that.

My app is a design tool. A lot of objects are added, deleted, and moved all the time. The length of the cylinders changes. Using your technique, I would have to adjust the size of your geometry all the time or set its size to infinity. Either way, that doesn’t sound elegant.

OK, before we go on, let us clarify one thing

it is most definitely YOUR geometry, not mine. Get this right.

Great, then you have all the code already in place to create a shadow clones of these objects :smiley: Now you think it is not elegant, but consider this: you dont have to have as much triangles on your cylinders if they arent visible. Hell, they could be 12-face boxes, lightning-fast both to create and to raycast against. Besides, this is what big boys do e g in Unity, look up their colliders.

This is a complex question, but you probably can express cylinder shape analytically

float sdCappedCylinder(vec3 p, vec3 a, vec3 b, float r)
{
  vec3  ba = b - a;
  vec3  pa = p - a;
  float baba = dot(ba,ba);
  float paba = dot(pa,ba);
  float x = length(pa*baba-ba*paba) - r*baba;
  float y = abs(paba-baba*0.5)-baba*0.5;
  float x2 = x*x;
  float y2 = y*y*baba;
  float d = (max(x,y)<0.0)?-min(x2,y2):(((x>0.0)?x2:0.0)+((y>0.0)?y2:0.0));
  return sign(d)*sqrt(abs(d))/baba;
}

and calculate minimum of signed distance field on ray path.

3 Likes

I guess this is the simplest approach so far. I will mark it as a solution unless somebody can come up with a better one.

You could also just override the raycast method of your mesh, copying the function of Mesh.js but expanding the triangle vertices of the test triangle along their normals before it is tested for ray intersection.

Other than that the suggestion of @munrocket would work too and be independend from the tessellation.

1 Like

extending by normals could easily create holes for hard edges; you would need smooth normals.

Also you can create spheres around each vertices a with relatively big diameter and raycast lot of spheres analytically too.

This solution will be not exactly precise but more universal (will fit for non-covex shapes) and with same performance like ordinary raycaster.

In other words you can create a lumpy surface around any object.

…with sufficient vertex density. obviously large triangles will create holes with this method.