1) 射线起点为O, 方向向量为D; 假设射线与三角形ABC的交点为P, 设P=O+t*D
2) 根据向量三点共线定理可知:AP=u*AB+v*AC,且u+v=1
因为向量AP=P-A, AB=B-A, AC=C-A, 所以P-A=u*(B-A)+v*(C-A)
>> P - A = u*B - u*A + v*C - v*A
>> P = A - u*A - v*A + u*B + v*C
根据1)和2)可得: O + t*D = A - u*A - v*A + u*B + v*C, 其中t, u, v为未知变量
>> O - A = -t*D + u*B - u*A + v*C - v*A
>> -t*D + u*(B-A) + v*(C-A) = O - A
3) 我们将上式用矩阵的形式来表示(等式左边的两个矩阵乘出来的结果就是-t*D + u*(B-A) + v*(C-A))
然后可以根据克莱姆法则(Cramer's rule),求出t, u, v
然后我们再利用下面的定理求行列式det:三阶方阵的行列式等于三个列向量的混合积。
得到:
4) 根据t, u, v的值判断是否相交以及交点。
相交的条件:0<=u<=1 且 0<=v<=1 且 u+v<=1
交点:P=O+t*D
public static bool RaycastTriangle(Vector2 O, Vector2 D, Vector2 A, Vector2 B, Vector2 C, out float dist) { dist = 0; Vector3 AB = B - A; Vector3 AC = C - A; Vector3 D_2 = -D; var cross_1 = Vector3.Cross(D_2, AC); float detDown = Vector3.Dot(AB, cross_1); if (Mathf.Approximately(detDown, 0)) //射线不在三角形平面上 return false; Vector3 AO = O - A; float u = Vector3.Dot(AO, cross_1) / detDown; if (u < 0 || u > 1) return false; float v = Vector3.Dot(AB, Vector3.Cross(D_2, AO)) / detDown; if (v < 0 || v > 1) return false; float t = Vector3.Dot(AB, Vector3.Cross(AO, AC)) / detDown; if (t > 0.000001f) //Epsilon { dist = t; return true; } return false; }
射线与三角形的位置关系
1) 射线起点o在三角形内
2) 射线起点o在三角形边上
3) 射线起点o与三角形顶点重叠
4) 射线起点o在三角形外
参考
一文读懂射线与三角形相交算法Moller-Trumbore算法【收藏好文】 - 知乎 (zhihu.com)
射线和三角形求交_射线求交_averagePerson的博客-CSDN博客
直线与三角形相交Moller Trumbore算法推导 | Blurred code
空间射线与三角形相交算法的两种实现_空间射线和三角面元求交-CSDN博客