这个相交测试算法的主要过程
1:判断一个三角形是否与另一个三角形所在的平面有交点,如果没有交点停止算法。返回为假
2:判断交点是否在三角形内,如果在,停止算法,返回为真
3:这个时候问题转化为2D上的三角形与三角形(两个三角形共面的情况),三角形和线段的检测情况。这里采用了投影方法来判断相交性。
在整个过程中,前面的计算结果在后面的计算中得到重复的利用,以此来降低计算的消耗。
Step 1
根据上面的图,列写下面的等式,分别求出Q0Q1Q2三角形和V0V1V2所在面的交点
V0+a0*p0+b0*p1 = Q0+c0*q0
V0+a1*p0+b1*p1 = Q1+c1*q1
V0+a2*p0+b2*p2 = Q2+c2*q2
这里要求的就是c0,c1,c2
转化为AX = B的形式
(p0,p1,q0)* [a0] = Q0-V0
[b0]
[-c0]
-c0 = |p0,p1,Q0-V0|/|p0,p1,Q1-Q0|
同样
-c1 = |p0,p1,Q1-V0|/|p0,p1,Q2-Q1|
-c2 = |p0,p1,Q2-V0|/|p0,p1,Q0-Q2|
注意:这里讨论两个三角形的一般的情况
上面的行列式中实际上只需要求|p0,p1,Q0|,|p0,p1,Q1|,|p0,p1,Q2|,|p0,p1,V0|这四个,另外这四个行列式的前两个列向量都是一样的,那么有些共同的运算是可以利用的。
因为
|a0,a1,a2| = (a0Xa1).a2
所以(a0Xa1)只需要算一次,然后依次和Q0,Q1,Q2,V0点乘一下,可以计算出四个行列式,进一步通过几个加减法得到需要的六个行列式的值。
如果两个三角形相交,那么c0,c1,c2必须满足[0,1],所以如果三个值中没有满足条件的,则可以判定两个三角形不想交。因此这一步是一个排斥检测
Step 2
如果存在满足条件的ci,计算出对应的交点,因为最多只有两个交点,记为T0,T1
现在判断T0,T1是否在V0V1V2三角形内
可以列方程
V0+a0*p0+b0*p1 = T0
V0+a1*p0+b1*p1 = T1
即
a0*p0+b0*p1 = T0-V0
a1*p0+b1*p1 = T1-V0
这只需要在二维上面讨论,因此(p0,p1)中要找到满足2x2行列式不为0的两行来求解方程组。这里又可以利用p0Xp1的结果(p0Xp1的每一个部分分别是(p0,p1)中2x2行列式的值),所以这里可以分别求出(a0,b0),(a1,b1)
如果Ti在三角形内,必有0<=ai<=1 0<=bi<=1 0<=ai+bi<=1
所以这里可以判断是否有相交的情况
Step 3
如果Step 2没有停止,则这个时候表示这两个点(如果是只有一个交点的情况在Step 2中已经停止)一定在三角形外,这个阶段使用投影方法来判断
Step 2中得到的(a0,b0),(a1,b1)实际上是一个在特殊的空间中的坐标,在这个空间中V0V1V2退化为一个特殊的三角形
如图所示
先在V0'V1'V2'三角形的边上投影
比如对x边
x边V0'V2',需要投影到y轴上去
如果 b0<0&&b1<0 || b0>1&&b1>1 那么这个线段T0'T1'与三角形无交点,可以直接返回,否则继续其他边的投影
特别的对于V1'V2',这需要在(1,1)这个向量轴上投影,可以化简为a0+b0<0&&a1+b1<0 || a0+b0>1&&a1+b1>1的条件判断
所以对于V0'V1'V2三角形的投影使用了Step 2的计算结果
如果三个边都没有停止,那么这个时候要对T0'T1'法向作为轴进行投影
T0'T1' = (a1-a0, b1-b0) 则法向为(b1-b0, a0-a1)记为(an,bn)
以T0为基点
(0,0)的投影为(a0,b0)*(an,bn)
(1,0)的投影为(a0-1,b0)*(an,bn) = (a0,b0)*(an,bn)-an
(0,1)的投影为(a0,b0-1)*(an,bn) = (a0,b0)*(an,bn)-bn
对于这里计算出来的三个值,如果同时大于0或者小于0则表示没有交点
经过所有的投影,都不能判定不相交的条件那么表示两个三角形存在交点。
特殊情况
1:平行但是不共面
如果|p0,p1,Q1-Q0|,|p0,p1,Q2-Q1|,|p0,p1,Q0-Q2|存在两个为0的情况,那么两个三角形是平行的
如果在平行的情况下|p0,p1,Q0-V0|,|p0,p1,Q1-V0|,|p0,p1,Q2-V0|不存在0,那么两个三角形平行不共面
2:共面
如果平行情况下,只需检测|p0,p1,Q0-V0|是否为0,为0表示共面
在这种情况下,不妨记为有三个交点,分别是Q0Q1Q2的三个顶点,然后对三个顶点采用Step 2和Step 3的方法进行判定,不同点在于Step 3中需要对T0'T1'T2’三角形的三个边进行投影判定
该算法的性能数据,测试环境 : AMD Athlon(tm) 64 X2 Dual Core Processor 4000+ 2.10 GHz, 1.96 GB
执行10 000 000次
总消耗时间: 2.2178 秒
平均消耗 : 0.2178 微秒
相交次数 : 6249996
针对每一种情况的性能数据
两个三角形平行但不共面 : 0.0812 微秒
平行共面但不相交 : 0.1688 微秒
平行共面相交,有点在三角形内 : 0.1265 微秒
平行共面相交,三角形包含情况 : 0.2391 微秒
非平行不相交,另一个三角形与面无交点 : 0.0968 微秒
非平行不相交,另一个三角形与面有一个交点 : 0.1563 微秒
非平行不相交,另一个三角形与面有两个交点 : 0.1617 微秒
非平行相交,有点在三角形内 : 0.1539 微秒
非平行相交,没有点在三角形内 : 0.2068 微秒