I have a case where I need to find the closest point to a sphere's center on a LOT of triangles. However, the accuracy isn't quite so important... it needs to be vaguely accurate, but an error rate of like 5% would be acceptable.
Currently I'm using two tests-- IsPointInTriangle and closest point on line for all three triangle edges. Specifically, this code:
Vector Math::GetClosestPointOnLine(Vector thePos, Vector theL1, Vector theL2)
{
//
// Do NOT try to optimize this like the 2D version... when I did it screwed up all the Hamsterball physics!
//
Vector aC=thePos-theL1;
Vector aV=theL2-theL1;
float aD=aV.Length();
aV/=aD;
float aT=Dot(aV,aC);
if (aT<0.0f) return (theL1);
if (aT>aD) return (theL2);
// Return the point between ‘a’ and ‘b’
//set length of V to t. V is normalized so this is easy
aV*=aT;
return (theL1+aV);
}
bool Math::IsPointInTriangle(Vector thePos, Vector theT1, Vector theT2, Vector theT3)
//bool IsPointInTriangle(const VECTOR& point,
// const VECTOR& pa,const VECTOR& pb, const VECTOR& pc)
{
Vector e10=theT2-theT1;
Vector e20=theT3-theT1;
float a = e10.Dot(e10);
float b = e10.Dot(e20);
float c = e20.Dot(e20);
float ac_bb=(a*c)-(b*b);
Vector vp(thePos.mX-theT1.mX, thePos.mY-theT1.mY, thePos.mZ-theT1.mZ);
float d = vp.Dot(e10);
float e = vp.Dot(e20);
float x = (d*c)-(e*b);
float y = (e*a)-(d*b);
float z = x+y-ac_bb;
return (( in(z)& ~(in(x)|in(y)) ) & 0x80000000)!=0;
}
Both of these are pretty fast, aside from a sqrt in closestpointonline. But it seems like there is probably a faster way. Any math wizards who can tell me a speedier-- at the cost of accuracy-- way to roughly say "closestpointontriangle, with maybe a 5% error threshold?"
Edit to add: The only alternative way I can think to do this would be to make four planes (plane of triangle + plane of edges in the direction of triangle normal) and fall to the triangle's plane then clip to all edge planes. But I'm not sure if that would be faster or not.