mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
102.02k stars 35.34k forks source link

Ray to line distance incorrect sometimes #18454

Closed NicolasRannou closed 4 years ago

NicolasRannou commented 4 years ago
Description of the problem

I've been testing the line picking and it seems sometimes the ray to line distance is incorrectly computed, resulting in the intersections from the raycaster to be incorrectly ordered.

It seems the "points" returned by the intersection is correct, but not the distance.

Live example: https://jsfiddle.net/nicolasrannou/d0mukjoq/33/

Three.js version
Browser
OS
Hardware Requirements (graphics card, VR Device, ...)
gkjohnson commented 4 years ago

I mentioned this in #17872 but I believe this is due to the linePrecision field causing every line to more or less be treated as a capsule shape which leads to some not-so-visually-intuitive intersection points. This means that lines closer to the camera will often get hit first and result in a point closer to the ray origin but not necessarily the closest (or most intuitive) to the line. As a work around you could manually discard all but the point closest to the ray after performing the raycast.

NicolasRannou commented 4 years ago

Thanks for the suggestion, the workaround should be ok for me (if that works).

Still, that feels not intuitive that the returned distance is not "correct" but that the intersection point is correct and can be used to re-compute the distance correctly!

Also, the line precision is not used to compute the distance at all, just to discard some segments of the line to be tested so it should not have any impact there.

gkjohnson commented 4 years ago

I don't know if I'd call it "incorrect". The need for something like "linePrecision" makes it all a bit more complicated and is a unique problem specific to line raycasting. Even if the distance was based on the point on the line that wouldn't fix the sort order and you'd still get the popping.

At the moment the point returned is one that is visibly on the line while the distance returned is the distance down the ray the indicates the closest point on the ray. Presumably this is so something like Ray.at can be used to derive the closest point on the ray (though there is a comment in the raycast function discussing what the right point to return should be.). If the distance from the point on the line to the ray origin were returned then that wouldn't be the case and others may call that incorrect.

I'm not sure if there's a one size fits all solution to this because I think what you want is the point from the intersection where the ray passes closest to the line and that can't be derived from distance.

NicolasRannou commented 4 years ago

Indeed the problem is very specific but unfortunatly I do not have time to dig into the radius/line precision thing that is still not totally clear to me.

My solution for a pixel perfect raycast was to implement GPU raycasting for the fat line. We can encode the line id in the R channel and the vertex index in the G and B indices. Also, line precision can then be set in pixels and is not impacted by zooming, which is a nice bonus for me!

Thanks for the feedback @gkjohnson ! (BTH I also use https://github.com/gkjohnson/three-mesh-bvh and that works really nicely! Great job!)

Jan-27-2020 09-05-35

Closing the issue!