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);
}