/// <summary> /// Determines the intersection between a ray and a triangle. /// </summary> /// <param name="ray">Ray to test.</param> /// <param name="maximumLength">Maximum length to travel in units of the direction's length.</param> /// <param name="a">First vertex of the triangle.</param> /// <param name="b">Second vertex of the triangle.</param> /// <param name="c">Third vertex of the triangle.</param> /// <param name="hitClockwise">True if the the triangle was hit on the clockwise face, false otherwise.</param> /// <param name="hit">Hit data of the ray, if any</param> /// <returns>Whether or not the ray and triangle intersect.</returns> public static bool FindRayTriangleIntersection(ref Ray ray, float maximumLength, ref Vector3 a, ref Vector3 b, ref Vector3 c, out bool hitClockwise, out RayHit hit) { hitClockwise = false; hit = new RayHit(); Vector3 ab = b - a; Vector3 ac = c - a; Vector3x.Cross(ref ab, ref ac, out hit.Normal); if (hit.Normal.LengthSquared() < Epsilon) return false; //Degenerate triangle! float d = -Vector3.Dot(ray.Direction, hit.Normal); hitClockwise = d >= 0; Vector3 ap = ray.Position - a; hit.T = Vector3.Dot(ap, hit.Normal); hit.T /= d; if (hit.T < 0 || hit.T > maximumLength) return false;//Hit is behind origin, or too far away. hit.Location = ray.Position + hit.T * ray.Direction; // Compute barycentric coordinates ap = hit.Location - a; float ABdotAB, ABdotAC, ABdotAP; float ACdotAC, ACdotAP; ABdotAB = Vector3.Dot(ab, ab); ABdotAC = Vector3.Dot(ab, ac); ABdotAP = Vector3.Dot(ab, ap); ACdotAC = Vector3.Dot(ac, ac); ACdotAP = Vector3.Dot(ac, ap); float denom = 1 / (ABdotAB * ACdotAC - ABdotAC * ABdotAC); float u = (ACdotAC * ABdotAP - ABdotAC * ACdotAP) * denom; float v = (ABdotAB * ACdotAP - ABdotAC * ABdotAP) * denom; return (u >= -Toolbox.BigEpsilon) && (v >= -Toolbox.BigEpsilon) && (u + v <= 1 + Toolbox.BigEpsilon); }
/// <summary> /// Determines the intersection between a ray and a triangle. /// </summary> /// <param name="ray">Ray to test.</param> /// <param name="maximumLength">Maximum length to travel in units of the direction's length.</param> /// <param name="sidedness">Sidedness of the triangle to test.</param> /// <param name="a">First vertex of the triangle.</param> /// <param name="b">Second vertex of the triangle.</param> /// <param name="c">Third vertex of the triangle.</param> /// <param name="hit">Hit data of the ray, if any</param> /// <returns>Whether or not the ray and triangle intersect.</returns> public static bool FindRayTriangleIntersection(ref Ray ray, float maximumLength, TriangleSidedness sidedness, ref Vector3 a, ref Vector3 b, ref Vector3 c, out RayHit hit) { hit = new RayHit(); Vector3 ab = b - a; Vector3 ac = c - a; Vector3x.Cross(ref ab, ref ac, out hit.Normal); if (hit.Normal.LengthSquared() < Epsilon) return false; //Degenerate triangle! float d = -Vector3.Dot(ray.Direction, hit.Normal); switch (sidedness) { case TriangleSidedness.DoubleSided: if (d <= 0) //Pointing the wrong way. Flip the normal. { hit.Normal = -hit.Normal; d = -d; } break; case TriangleSidedness.Clockwise: if (d <= 0) //Pointing the wrong way. Can't hit. return false; break; case TriangleSidedness.Counterclockwise: if (d >= 0) //Pointing the wrong way. Can't hit. return false; hit.Normal = -hit.Normal; d = -d; break; } Vector3 ap = ray.Position - a; hit.T = Vector3.Dot(ap, hit.Normal); hit.T /= d; if (hit.T < 0 || hit.T > maximumLength) return false;//Hit is behind origin, or too far away. hit.Location = ray.Position + hit.T * ray.Direction; // Compute barycentric coordinates ap = hit.Location - a; float ABdotAB, ABdotAC, ABdotAP; float ACdotAC, ACdotAP; ABdotAB = Vector3.Dot(ab, ab); ABdotAC = Vector3.Dot(ab, ac); ABdotAP = Vector3.Dot(ab, ap); ACdotAC = Vector3.Dot(ac, ac); ACdotAP = Vector3.Dot(ac, ap); float denom = 1 / (ABdotAB * ACdotAC - ABdotAC * ABdotAC); float u = (ACdotAC * ABdotAP - ABdotAC * ACdotAP) * denom; float v = (ABdotAB * ACdotAP - ABdotAC * ABdotAP) * denom; return (u >= -Toolbox.BigEpsilon) && (v >= -Toolbox.BigEpsilon) && (u + v <= 1 + Toolbox.BigEpsilon); }