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, ac;
Vector3.Subtract(ref b, ref a, out ab);
Vector3.Subtract(ref c, ref a, out ac);
Vector3.Cross(ref ab, ref ac, out hit.Normal);
if (hit.Normal.LengthSquared() < Epsilon)
return false; //Degenerate triangle!
float d;
Vector3.Dot(ref ray.Direction, ref hit.Normal, out d);
d = -d;
switch (sidedness)
{
case TriangleSidedness.DoubleSided:
if (d <= 0) //Pointing the wrong way. Flip the normal.
{
Vector3.Negate(ref hit.Normal, out 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;
Vector3.Negate(ref hit.Normal, out hit.Normal);
d = -d;
break;
}
Vector3 ap;
Vector3.Subtract(ref ray.Position, ref a, out ap);
Vector3.Dot(ref ap, ref hit.Normal, out hit.T);
hit.T /= d;
if (hit.T < 0 || hit.T > maximumLength)
return false;//Hit is behind origin, or too far away.
Vector3.Multiply(ref ray.Direction, hit.T, out hit.Location);
Vector3.Add(ref ray.Position, ref hit.Location, out hit.Location);
// Compute barycentric coordinates
Vector3.Subtract(ref hit.Location, ref a, out ap);
float ABdotAB, ABdotAC, ABdotAP;
float ACdotAC, ACdotAP;
Vector3.Dot(ref ab, ref ab, out ABdotAB);
Vector3.Dot(ref ab, ref ac, out ABdotAC);
Vector3.Dot(ref ab, ref ap, out ABdotAP);
Vector3.Dot(ref ac, ref ac, out ACdotAC);
Vector3.Dot(ref ac, ref ap, out ACdotAP);
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);
}