一、利用分离轴定理检测
检测由方盒质心指向方盒各顶点的向量与方盒质心指向三角形各顶点的向量在分离轴上的投影是否有重叠,以下为方盒与三角网格中的一个三角形的碰撞检测,源代码为开源Open Dynamics Engine。
1.检测方盒面的法向量
方盒的旋转矩阵的三列分别代表面的法向量(
n
\boldsymbol {n}
n与
−
n
\boldsymbol {-n}
−n分别代表相对的两个面的法向量),首先,固定一个待测定的法向量
v
L
vL
vL,由方盒质心指向三角形三个顶点的向量与该法向量点乘得到
f
p
0
,
f
p
1
,
f
p
2
fp0,fp1,fp2
fp0,fp1,fp2,沿着该法向量的边的长度的一半为
f
R
fR
fR
无重叠:
有重叠:
SUBTRACT(v0,m_vHullBoxPos,vD);
fp0 = dCalcVectorDot3(vL,vD);
fp1 = fp0 + dCalcVectorDot3(vA0,m_vE0);
fp2 = fp0 + dCalcVectorDot3(vA0,m_vE1);
dReal fa0 = m_vBoxHalfSize[0];
dReal fa1 = m_vBoxHalfSize[1];
dReal fa2 = m_vBoxHalfSize[2];
fR = fa0;
//fMin=min(fp0,fp1,fp2),fMax=max(fp0,fp1,fp2)
dReal fDepthMin = fR - fMin;
dReal fDepthMax = fMax + fR;
若
f
D
e
p
t
h
M
i
n
<
0
fDepthMin<0
fDepthMin<0,即
f
M
i
n
>
f
R
fMin>fR
fMin>fR,此时三角形位于
v
L
vL
vL指向的一侧. 那么显然我们已经找到了一个分离轴,同理,若
f
D
e
p
t
h
M
a
x
<
0
fDepthMax<0
fDepthMax<0,即
−
f
M
a
x
>
f
R
-fMax>fR
−fMax>fR,此时三角形位于
−
v
L
-vL
−vL指向的一侧,此时也找到了一个分离轴。故方盒与三角形无相交。
除上述两种情况外,方盒与三角形相交,若离方盒更远的点在
−
v
L
-vL
−vL一侧,那么有
f
D
e
p
t
h
M
i
n
>
f
D
e
p
t
h
M
a
x
fDepthMin > fDepthMax
fDepthMin>fDepthMax,此时法向量应取
−
v
L
-vL
−vL,深度是
f
D
e
p
t
h
M
a
x
fDepthMax
fDepthMax
// if greater depth is on negative side
if ( fDepthMin > fDepthMax ) {
// use smaller depth (one from positive side)
fDepth = fDepthMax;
// flip normal direction
vNormal[0] = -vNormal[0];
vNormal[1] = -vNormal[1];
vNormal[2] = -vNormal[2];
fD = -fD;
// if greater depth is on positive side
} else {
// use smaller depth (one from negative side)
fDepth = fDepthMin;
}
2.检测三角形的法向量
检测三角形的法向量
v
L
=
m
v
N
vL=mvN
vL=mvN是否可以作为分离轴:
以方盒质心为原点,旋转矩阵的三列为基坐标,则方盒顶点的坐标为
(
±
f
a
0
,
±
f
a
1
,
±
f
a
2
)
(\pm fa0,\pm fa1,\pm fa2)
(±fa0,±fa1,±fa2),各顶点在世界坐标系下为
±
f
a
0
∗
v
A
0
±
f
a
1
∗
v
A
1
±
f
a
2
∗
v
A
2
+
p
\pm fa0*vA0 \pm fa1*vA1\pm fa2*vA2+p
±fa0∗vA0±fa1∗vA1±fa2∗vA2+p,p为质心。那么质心到各顶点的向量为
±
f
a
0
∗
v
A
0
±
f
a
1
∗
v
A
1
±
f
a
2
∗
v
A
2
\pm fa0*vA0 \pm fa1*vA1\pm fa2*vA2
±fa0∗vA0±fa1∗vA1±fa2∗vA2。法向量上的投影为
m
v
N
⋅
(
±
f
a
0
∗
v
A
0
±
f
a
1
∗
v
A
1
±
f
a
2
∗
v
A
2
)
mvN \cdot (\pm fa0*vA0 \pm fa1*vA1\pm fa2*vA2)
mvN⋅(±fa0∗vA0±fa1∗vA1±fa2∗vA2)
方盒质心到三角形顶点的向量vD在法向量上的投影为
m
v
N
⋅
v
D
mvN\cdot vD
mvN⋅vD。
fp0 = dCalcVectorDot3(vL,vD);
fR=fa0*dFabs( dCalcVectorDot3(m_vN,vA0) ) + fa1 * dFabs( dCalcVectorDot3(m_vN,vA1) ) +
fa2 * dFabs( dCalcVectorDot3(m_vN,vA2) )
dReal fDepth = fR+fp0;
若 f D e p t h < 0 fDepth<0 fDepth<0,二者不相交,反之,二者相交,法向量为单位化后的 − v L -vL −vL。
3.检测方盒的轴与三角形边的叉乘
由质心指向方盒的8个顶点的向量在法向量上的投影为
v
L
⋅
(
±
f
a
0
∗
v
A
0
±
f
a
1
∗
v
A
1
±
f
a
2
∗
v
A
2
)
vL \cdot (\pm fa0*vA0 \pm fa1*vA1\pm fa2*vA2)
vL⋅(±fa0∗vA0±fa1∗vA1±fa2∗vA2),其中法向量是方盒的边与三角形边的叉乘,不妨首先设
v
L
=
v
A
0
×
m
v
E
0
vL=vA0\times mvE0
vL=vA0×mvE0,故投影为
v
A
0
×
m
v
E
0
⋅
(
±
f
a
0
∗
v
A
0
±
f
a
1
∗
v
A
1
±
f
a
2
∗
v
A
2
)
=
v
A
0
×
m
v
E
0
⋅
(
±
f
a
1
∗
v
A
1
±
f
a
2
∗
v
A
2
)
=
±
f
a
1
∗
v
A
2
⋅
m
v
E
0
±
f
a
2
∗
v
A
1
⋅
m
v
E
0
\begin{array}{c} vA0\times mvE0 \cdot (\pm fa0*vA0 \pm fa1*vA1\pm fa2*vA2) \\ =vA0\times mvE0 \cdot (\pm fa1*vA1\pm fa2*vA2)\\ =\pm fa1*vA2 \cdot mvE0 \pm fa2*vA1 \cdot mvE0 \end{array}
vA0×mvE0⋅(±fa0∗vA0±fa1∗vA1±fa2∗vA2)=vA0×mvE0⋅(±fa1∗vA1±fa2∗vA2)=±fa1∗vA2⋅mvE0±fa2∗vA1⋅mvE0
由质心指向三角形三个顶点的向量在法向量上的投影分别为:
f
p
0
=
v
L
⋅
(
V
0
−
P
)
=
v
A
0
×
(
V
1
−
V
0
)
⋅
(
V
0
−
P
)
f
p
1
=
v
L
⋅
(
V
1
−
P
)
=
v
A
0
×
(
V
1
−
V
0
)
⋅
(
V
1
−
P
)
f
p
2
=
v
L
⋅
(
V
2
−
P
)
=
v
A
0
×
(
V
1
−
V
0
)
⋅
(
V
2
−
P
)
\begin{array}{c} fp0 = vL \cdot (V0-P) = vA0\times (V1-V0)\cdot (V0-P)\\ fp1 = vL \cdot (V1-P) = vA0\times (V1-V0)\cdot (V1-P)\\ fp2 = vL \cdot (V2-P) = vA0\times (V1-V0)\cdot (V2-P)\\ \end{array}
fp0=vL⋅(V0−P)=vA0×(V1−V0)⋅(V0−P)fp1=vL⋅(V1−P)=vA0×(V1−V0)⋅(V1−P)fp2=vL⋅(V2−P)=vA0×(V1−V0)⋅(V2−P)
利用混合积运算可以推导得到
f
p
1
=
f
p
0
,
f
p
2
=
f
p
0
+
v
A
0
⋅
m
v
N
fp1=fp0,fp2=fp0+vA0 \cdot mvN
fp1=fp0,fp2=fp0+vA0⋅mvN
最后判断是否重合.
4.代码
ODE collision_trimesh_box.cpp