最近需要用到這個求交計算,開始看了《計算機圖形學幾何工具算法詳解》,裏面的講解很詳細,但是給出的代碼有點問題,而且用到的類/結構體的定義並沒有給出,所以只能自己猜測,後來發現有的時候求出的結果有誤,所以又在網上搜了一下,自己再整理如下,大家可以直接拷貝粘貼過去使用。
該算法主要思想是先求出線段與三角形所在平面的交點,然後判斷該交點是否位於三角形內部。
利用三角形(頂點爲V0, V1, V2)內任意一點Q可以用重心座標表示爲 Q = w*V0 + u*V1 + v*V2; 其中w+u+v=1,三元組(w, u, v)稱爲Q的重心座標。設線段方程爲 L: p + t*d; p爲一個端點,d 爲兩個端點的差,即方向。
由 p + t*d = (1-u-v)*V0 + u*V1 + v*V2; 可以求出t, u, v的值。當 0=<u, v<=1 並且 0=<u+v<=1時,交點位於三角形內。
struct tri3d
{
float v0[3];
float v1[3];
float v2[3];
};
float vector_dot(float v0[3], float3 v1[3])
{
return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2];
}
void vector_minus(float a[3], float b[3], float res[3])
{
res[0] = a[0]-b[0];
res[1] = a[1]-b[1];
res[2] = a[2]-b[2];
}
void vector_cross(float a[3], float b[3], float res[3])
{
res[0] = a[1]*b[2]-a[2]*b[1];
res[1] = a[2]*b[0]-a[0]*b[2];
res[2] = a[0]*b[1]-a[1]*b[0];
}
bool LineTriangleIntersect(float start[3], float end[3], tri3d tri, float intersection[3])
{
const float epsilon = 0.000001f;
float e1[3], e2[3], p[3], s[3], q[3];
float t, u, v, tmp;
float direction[3];
vector_minus(end, start, direction);
vector_minus(tri.v1, tri.v0, e1);
vector_minus(tri.v2, tri.v0, e2);
vector_cross(direction, e2, p);
tmp = vector_dot(p, e1);
if (tmp > -epsilon && tmp < epsilon)
return false;
tmp = 1.0f / tmp;
vector_minus(start, tri.v0, s);
u = tmp * vector_dot(s, p);
if (u < 0.0 || u > 1.0)
return false;
vector_cross(s, e1, q);
v = tmp * vector_dot(direction, q);
if (v < 0.0 || v > 1.0)
return false;
if (u + v > 1.0)
return false;
t = tmp * vector_dot(e2, q);
if (t < 0.0 || t > 1.0)
return false;
intersection[0] = start[0] + t * direction[0];
intersection[1] = start[1] + t * direction[1];
intersection[2] = start[2] + t * direction[2];
return true;
}