射线检测 - 射线与三角形交点 - Moller Trumbore算法

发布时间 2023-11-23 01:40:48作者: yanghui01

 

 

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博客