0

I find the trilinear coordinates of the coordinate of the point of intersection through the barycentric coordinates. Barycentric coordinates are correct (seemingly).

    private const double Epsilon = 0.000001d;

    public static Vector3? GetPointIntersectionRayAndTriangle(Vector3 rayOrigin, Vector3 rayDirection, Vector3 vert0, Vector3 vert1, Vector3 vert2)
    {
        Vector3 edge1 = new Vector3();
        Vector3 edge2 = new Vector3();

        Vector3 tvec = new Vector3();
        Vector3 pvec = new Vector3();
        Vector3 qvec = new Vector3();

        double det, invDet;

        edge1 = vert1 - vert0;
        edge2 = vert2 - vert0;

        pvec = Cross(rayDirection, edge2);

        det = Dot(edge1, pvec);

        if (det > -Epsilon && det < Epsilon)
        {
            return null;
        }

        invDet = 1d / det;

        tvec = rayOrigin - vert0;

        double t, u, v;

        u = Dot(tvec, pvec) * invDet;

        if (u < 0 || u > 1)
        {
            return null;
        }

        qvec = Cross(tvec, edge1);

        v = Dot(rayDirection, qvec) * invDet;

        if (v < 0 || u + v > 1)
        {
            return null;
        }

        t = Dot(edge2, qvec) * invDet;

        return GetTrilinearCoordinates(t, u, v, vert0, vert1, vert2);
    }

    private static double Dot(Vector3 v1, Vector3 v2)
    {
        return v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z;
    }

    private static Vector3 Cross(Vector3 v1, Vector3 v2)
    {
        Vector3 dest;

        dest.X = v1.Y * v2.Z - v1.Z * v2.Y;
        dest.Y = v1.Z * v2.X - v1.X * v2.Z;
        dest.Z = v1.X * v2.Y - v1.Y * v2.X;

        return dest;
    }

    private static Vector3 GetTrilinearCoordinates(double t, double u, double v, Vector3 vert0, Vector3 vert1, Vector3 vert2)
    {
        float a = (vert0 - vert1).Length();
        float b = (vert1 - vert2).Length();
        float c = (vert2 - vert0).Length();

        return new Vector3((float)t / a, (float)u / b, (float)v / c);
    }
  • rayOrigin - beginning of the ray.
  • vert0, vert1, vert2 - coordinates of the triangle.

I use this unit test to check:

    [TestMethod]
    public void GetPointIntersectionRayAndTriangleCheckOnResult()
    {
        Vector3? vector1 = ComputationsInThreeDimensionalSpace.GetPointIntersectionRayAndTriangle(
            new Vector3(1, 1, 2),
            new Vector3(0, 0, -4),
            new Vector3(0, 0, 0),
            new Vector3(4, -1, 0),
            new Vector3(0, 5, 0));

        if (!vector1.HasValue)
        {
            Assert.Fail();
        }

        Assert.AreEqual(new Vector3(1, 1, 0), vector1.Value);
    }

Are there other ways to find the point of intersection of a ray with a triangle? It is desirable without barycentric coordinates.

A_M
  • 49
  • 9
  • 1
    Why is it "desirable" without barycentric coordinates? The above algorithm (Möller-Trumbore) is one of the most well-known and efficient methods to perform this test. Also, be careful when testing for equality with floating point numbers. – meowgoesthedog Aug 11 '18 at 08:10
  • This is desirable, because trilinear coordinates are more familiar to me. Yes, I know about floating-point numbers, but the algorithm still does not give what I need. Failed Assert.AreEqual. Expected: << 1 1 0 >>. In fact: << 0,1212678 0,03466876 0,05 >>. – A_M Aug 11 '18 at 08:26

2 Answers2

1

t is not a barycentric coordinate, but the distance from the origin to the intersection, so should not be passed to GetTrilinearCoordinates. Instead you should pass 1 - u - v, because Moller-Trumbore returns normalized Barycentric coordinates.

meowgoesthedog
  • 14,670
  • 4
  • 27
  • 40
  • I do not understand what needs to be done. I have the usual trilinear coordinates (xyz) of the ray, its directions and the points of the triangle. I just need to get xyz intersection points. – A_M Aug 11 '18 at 12:11
  • I do not understand how to convert t and uv into regular xyz – A_M Aug 11 '18 at 13:08
  • All. Got it. Thank you so much – A_M Aug 11 '18 at 13:19
  • 1
    Sorry for the late reply: `p = (1 - u - v) * a + u * b + v * c` where `a b c` are the vertices (in the correct order). – meowgoesthedog Aug 11 '18 at 13:35
0

This is the working code for finding the point where the ray hits the triangle. GetTimeAndUvCoord returns null if the beam does not hit the triangle

The function GetTimeAndUvCoord finds T and UV. The GetTrilinearCoordinateOfTheHit function returns XYZ.

    private const double Epsilon = 0.000001d;

    public static Vector3? GetTimeAndUvCoord(Vector3 rayOrigin, Vector3 rayDirection, Vector3 vert0, Vector3 vert1, Vector3 vert2)
    {
        var edge1 = vert1 - vert0;
        var edge2 = vert2 - vert0;

        var pvec = Cross(rayDirection, edge2);

        var det = Dot(edge1, pvec);

        if (det > -Epsilon && det < Epsilon)
        {
            return null;
        }

        var invDet = 1d / det;

        var tvec = rayOrigin - vert0;

        var u = Dot(tvec, pvec) * invDet;

        if (u < 0 || u > 1)
        {
            return null;
        }

        var qvec = Cross(tvec, edge1);

        var v = Dot(rayDirection, qvec) * invDet;

        if (v < 0 || u + v > 1)
        {
            return null;
        }

        var t = Dot(edge2, qvec) * invDet;

        return new Vector3((float)t, (float)u, (float)v);
    }

    private static double Dot(Vector3 v1, Vector3 v2)
    {
        return v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z;
    }

    private static Vector3 Cross(Vector3 v1, Vector3 v2)
    {
        Vector3 dest;

        dest.X = v1.Y * v2.Z - v1.Z * v2.Y;
        dest.Y = v1.Z * v2.X - v1.X * v2.Z;
        dest.Z = v1.X * v2.Y - v1.Y * v2.X;

        return dest;
    }

    public static Vector3 GetTrilinearCoordinateOfTheHit(float t, Vector3 rayOrigin, Vector3 rayDirection)
    {
        return rayDirection * t + rayOrigin;
    }
A_M
  • 49
  • 9