public static void GetBarycentricCoordinates(ref Vector3 p, ref Vector3 a, ref Vector3 b, ref Vector3 c, out float aWeight, out float bWeight, out float cWeight)
{
Vector3 ab, ac;
Vector3.Subtract(ref b, ref a, out ab);
Vector3.Subtract(ref c, ref a, out ac);
Vector3 triangleNormal;
Vector3.Cross(ref ab, ref ac, out triangleNormal);
float x = triangleNormal.X < 0 ? -triangleNormal.X : triangleNormal.X;
float y = triangleNormal.Y < 0 ? -triangleNormal.Y : triangleNormal.Y;
float z = triangleNormal.Z < 0 ? -triangleNormal.Z : triangleNormal.Z;
float numeratorU, numeratorV, denominator;
if (x >= y && x >= z)
{
//The projection of the triangle on the YZ plane is the largest.
numeratorU = (p.Y - b.Y) * (b.Z - c.Z) - (b.Y - c.Y) * (p.Z - b.Z); //PBC
numeratorV = (p.Y - c.Y) * (c.Z - a.Z) - (c.Y - a.Y) * (p.Z - c.Z); //PCA
denominator = triangleNormal.X;
}
else if (y >= z)
{
//The projection of the triangle on the XZ plane is the largest.
numeratorU = (p.X - b.X) * (b.Z - c.Z) - (b.X - c.X) * (p.Z - b.Z); //PBC
numeratorV = (p.X - c.X) * (c.Z - a.Z) - (c.X - a.X) * (p.Z - c.Z); //PCA
denominator = -triangleNormal.Y;
}
else
{
//The projection of the triangle on the XY plane is the largest.
numeratorU = (p.X - b.X) * (b.Y - c.Y) - (b.X - c.X) * (p.Y - b.Y); //PBC
numeratorV = (p.X - c.X) * (c.Y - a.Y) - (c.X - a.X) * (p.Y - c.Y); //PCA
denominator = triangleNormal.Z;
}
if (denominator < -1e-9 || denominator > 1e-9)
{
denominator = 1 / denominator;
aWeight = numeratorU * denominator;
bWeight = numeratorV * denominator;
cWeight = 1 - aWeight - bWeight;
}
else
{
//It seems to be a degenerate triangle.
//In that case, pick one of the closest vertices.
//MOST of the time, this will happen when the vertices
//are all very close together (all three points form a single point).
//Sometimes, though, it could be that it's more of a line.
//If it's a little inefficient, don't worry- this is a corner case anyway.
float distance1, distance2, distance3;
Vector3.DistanceSquared(ref p, ref a, out distance1);
Vector3.DistanceSquared(ref p, ref b, out distance2);
Vector3.DistanceSquared(ref p, ref c, out distance3);
if (distance1 < distance2 && distance1 < distance3)
{
aWeight = 1;
bWeight = 0;
cWeight = 0;
}
else if (distance2 < distance3)
{
aWeight = 0;
bWeight = 1;
cWeight = 0;
}
else
{
aWeight = 0;
bWeight = 0;
cWeight = 1;
}
}
}