7
votes

I'm facing problem intersecting ray with triangle edges. Actually, I'm trying to pick/intersect with triangle, vertex, edge of a mesh using Mouse. So I made ray from the Mouse current position and then I intersect it with the mesh elements like triangle/polygon, vertex, edge etc to work with it. Basically, 3d modeling stuffs. Intersecting with triangle was easy and fun. And the vertex part was tricky.

But now, I don't know how to intersect/pick with triangle edges. I mean how I treat them when intersecting with the Mouse Ray? First I thought they can be treated like a 3D line. But eventually failed to do the Ray and the Line intersect. Searched on the Internet but not found any helpful info. Although I found some open source projects are using OpenGL built-in picking features to pick/intersect with Edge. But in my case, I can't use that. :(

My current edge picking code structure looks like the following:

void pickEdge(Ray ray, Scene scene)
{
    for each object in scene
    {
        mesh = getMesh(object)
        for each triangle in mesh
        {
            for each edge in triangle
            {
                v1 = getV1(edge)
                v2 = getV2(edge)

                // Do intersect with 'ray' and 'v1', 'v2'. But how?
            }
        }
    }
}

So I'm stuck here and really need some help. Any idea, algorithm or a small help is greatly appreciated.

4
Determine if your picking point is within an acceptable 'radius' of the edge - using a distance to line formula. Then an orthogonal projection to the edge to yield a 'point' on the edge if necessary.Brett Hale
@Brett Hale You say 'using a distance to line formula'. Actually I'm stuck at this point. In fact I'm not yet able to implement the Ray-Line intersect. It would be much more helpful if you post it as a answer with more details. Thanks for your valuable comment :)Farhad Reza
Ah... actually I'm still stuck :( Need help... Please.Farhad Reza

4 Answers

1
votes

In your case problem of finding intersection between triangle and ray in 3D space can be boiled down to finding point location (INSIDE, OUTSIDE, ON BOUNDARY) in triangle in 2D space (plane). All you should do is project triangle on screen plane, find intersection on edge and perform reverse projection on edge. Position of point is position of mouse. The only problem is to treat degenerate cases like mapping triangle into line segment. But I think it will not be problem, because such cases can be easily coped.

1
votes

Please give a look to the algorithms at the end of this page and more in general all the ones that this website offers: http://geomalgorithms.com/a05-_intersect-1.html

1
votes

The first approach is to orthogonally project the edge (and the ray) to a plane perpendicular to the ray, and then to compute the distance of the projected ray to the projected edge.

Ie., first you determine two orthogonal vectors rdir1, rdir2 orthogonal to your ray.

Then you calculate the projection of your ray (its base point) to this plane, which will simply yield a 2d point rp.

Then you project the edge to that plane, by simply applying dot products: pv1 = new Vector2(DotProduct(v1, rdir1), DotProduct(v1, rdir2)) pv2 = new Vector2(DotProduct(v2, rdir1), DotProduct(v2, rdir2))

Now you can compute the distance from this 2d line pv1, pv2 to the point rp.

Provided that the direction of the edge is taken from the view matrix's "forward" direction, then two vectors orthogonal to that would be the view matrix's left and right vectors.

Doing the above recipe will then yield something similar to projecting the edge to the screen. Hence, alternatively you could project the edge to the screen and work with those coordinates.

0
votes

First of all, what is the distance between two geometric objects A and B ? It is the minimal distance between any two points on A and B, ie. dist(A,B) = min { EuclideanLength(x - y) | x in A, y in B}. (If it exists and is unique, which it does in your case.)

Here EuclideanLength((x,y,z)) = sqrt(x^2 + y^2 + z^2) as you already know. Because sqrt is strictly increasing it suffices to minimize SquareEuclideanLength((x,y,z)) = x^2 + y^2 + z^2, which greatly simplifies the problem.

In your question the objects are a line segment A := {v1 + t*(v2-v1) | 0 <= t <= 1} and a line B := {p + s*d | s is any real number}. (Don't worry that you asked about a ray, a line is really what you want.)

Now calculating the distance comes down to finding appropriate t and s such that SquareEuclideanLength(v1 + t*(v2-v1) - p - s*d) is minimal and then computing EuclideanLength(v1 + t*(v2-v1) - p - s*d) to get the real distance.

To solve this we need some analytic geometry. Because d is not zero, we can write each vector v as a sum of a part that is orthogonal to d and a part that is a multiple of d: v = Ov + Mv. For such an "orthogonal decomposition" it always holds SquareEuclideanLength(v) = SquareEuclideanLength(Ov) + SquareEuclideanLength(Mv).

Because of d = Md in the above

SquareEuclideanLength(v1 + t*(v2-v1) - p - s*d) = SquareEuclideanLength(Ov1 + t*(Ov2-Ov1) - Op) + SquareEuclideanLength(Mv1 + t*(Mv2-Mv1) - Mp - s*d)

the left addend does not depend on s and however you chose t you can find an s such that the right addend is 0 ! (Remember that Mv1, Mv2, ... are multiples of d.)

Hence to find the minimum you just have to find such maps O, M as above and find the minimizer t.

Assuming that d is normalized, these are actually given by Ov := CrossProduct(v, d) and Mv := DotProduct(v, d)*d, but just believe me, that this also works if d is not normalized.

So the recipe for finding the distance is now: find 0 <= t <= 1 that minimizes

SquareEuclideanLength(Cross(v1 - p, d) + t*Cross(v2 - v1, d)) = SquareEuclideanLength(Cross(v1 - p, d)) + 2*t*Dot(Cross(v1 - p, d), Cross(v2 - v1, d)) + t^2 SquareEuclideanLength(Cross(v2 - v1, d)).

You will already know this formula from Point-Line distance calculation (that's what it is) and it is solved by differentiating with respect to t and equalling 0.

So the minimizer of this equation is t = -Dot(Cross(v1 - p, d), Cross(v2 - v1, d))/SquareEuclideanLength(Cross(v2 - v1, d))

Using this t you calculate v1 + t*(v2 - v1), the point on the line segment A that is closest to line B and you can plug this into your point-line distance algorithm to find the sought after distance.

I hope this helps you !