FmVec3 GetClosestPointTriangle(FmVec3 p, FmVec3 a, FmVec3 b, FmVec3 c) { FmVec3 result; FmVec3 ab, ac, ap; ab = b - a; ac = c - a; ap = p - a; float d1 = ab.dot(ap); float d2 = ac.dot(ap); if (d1 <= 0.0f && d2 <= 0.0f) { result = a; return result; } FmVec3 bp; bp = p - b; float d3 = ab.dot(bp); float d4 = ac.dot(bp); if (d3 >= 0.0f && d4 <= d3) { // barycentric coordinates (0,1,0) result = b; return result; } // Check if P in edge region of AB, if so return projection of P onto AB float vc = d1 * d4 - d3 * d2; if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) { // barycentric coordinates (1-v,v,0) float v = d1 / (d1 - d3); result.x = a.x + v * ab.x; result.y = a.y + v * ab.y; result.z = a.z + v * ab.z; return result; } FmVec3 cp = p - c; float d5 = ab.dot(cp); float d6 = ac.dot(cp); if (d6 >= 0.0f && d5 <= d6) { // barycentric coordinates (0,0,1) result = c; return result; } // Check if P in edge region of AC, if so return projection of P onto AC float vb = d5 * d2 - d1 * d6; if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) { // barycentric coordinates (1-w,0,w) float w = d2 / (d2 - d6); result.x = a.x + w * ac.x; result.y = a.y + w * ac.y; result.z = a.z + w * ac.z; return result; } // Check if P in edge region of BC, if so return projection of P onto BC float va = d3 * d6 - d5 * d4; if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f) { // barycentric coordinates (0,1-w,w) float w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); result.x = b.x + w * (c.x - b.x); result.y = b.y + w * (c.y - b.y); result.z = b.z + w * (c.z - b.z); return result; } // P inside face region. Compute Q through its barycentric coordinates (u,v,w) float denom = 1.0f / (va + vb + vc); float v = vb * denom; float w = vc * denom; result.x = a.x + ab.x * v + ac.x * w; result.y = a.y + ab.y * v + ac.y * w; result.z = a.z + ab.z * v + ac.z * w; return result; }