赞
踩
碰撞检测是3维游戏内必不可少的一个功能,有了碰撞检测,游戏才能显得更加真实。之前查找碰撞检测的资料,很多都提到了SAT以及GJK算法,但是少有对这两个算法进行深入解析的。于是本人花了一个星期左右去阅读GJK的论文,现在将论文内的细节进行整理,和大家分享。碰撞检测涉及到相当多数学知识,所以这个主题应该会有好几个部分组成。文章内可能会出现一些错的或者是不严谨的地方,也还请大家指正
论文地址:http://web.eecs.umich.edu/~grizzle/GilbertFest/Gilbert(58).pdf
论文的第一部分是总结前人工作以及对不同算法的比较,不涉及算法内容,因此跳过,直接从第二部分开始。还有一点是,公式后面的标号会和论文对应,所以可能不按顺序。
假设现在存在两个三维空间内的紧集
K
A
,
K
B
∈
R
3
K_A, K_B \in R^3
KA,KB∈R3,然后定义如下符号:
d
(
K
A
,
K
B
)
=
m
i
n
{
∣
x
−
y
∣
:
x
∈
K
A
,
y
∈
K
B
}
(
1
)
d(K_A, K_B ) = min \lbrace |x - y|: x \in K_A, y \in K_B \rbrace \kern3em \lparen1\rparen
d(KA,KB)=min{∣x−y∣:x∈KA,y∈KB}(1)显然,上式表示的是这两个集合中最近的点的距离,下图线段cd的长度就代表了两个圆最短的距离(为了画图方便,这里用了二维的图)
如果集合A和B是由多个子集构成,这些子集满足:
K
A
=
⋃
i
∈
I
A
K
i
K
B
=
⋃
j
∈
I
B
K
j
(
2
)
K_A = \bigcup_{i \in I_A} K_i \kern3em K_B = \bigcup_{j \in I_B} K_j \kern5em \lparen2\rparen
KA=i∈IA⋃KiKB=j∈IB⋃Kj(2)其中
I
A
I_A
IA和
I
B
I_B
IB是索引集(index set)。按照(1)式的定义,有:
d
(
K
A
,
K
B
)
=
m
i
n
{
d
i
j
:
i
∈
I
A
,
j
∈
I
B
}
(
3
)
d(K_A, K_B ) = min \lbrace d_{ij}: i \in I_A, j \in I_B \rbrace \kern3em \lparen3\rparen
d(KA,KB)=min{dij:i∈IA,j∈IB}(3)其中
d
i
j
d_{ij}
dij定义为:
d
i
j
=
m
i
n
{
∣
x
−
y
∣
:
x
∈
K
i
,
y
∈
K
j
}
(
4
)
d_{ij} = min \lbrace |x - y|: x \in K_i, y \in K_j \rbrace \kern4em \lparen4\rparen
dij=min{∣x−y∣:x∈Ki,y∈Kj}(4)即
d
i
j
d_{ij}
dij表示的是子集
K
i
K_i
Ki和
K
j
K_j
Kj之间的最短距离,然后返回公式(3)可得,两个集合之间的最短距离是各自子集最短距离的最小值。论文中的图很好的表现了这一点,这里我不作过多阐述。
接下来是r-球面扩展。举两个例子,三维空间中,点的r-球面扩展就是一个球,线段的r-球面扩展就是两头为球面的圆柱(上图中的
K
2
K_2
K2),这里的r指的是半径。其公式如下:
K
r
=
{
x
:
∣
x
−
y
∣
⩽
r
,
y
∈
K
}
(
5
)
K^r = \lbrace x: |x - y| \leqslant r, y \in K\rbrace \kern3em \lparen5\rparen
Kr={x:∣x−y∣⩽r,y∈K}(5)显然,在进行球面扩展之后两个闭集的最短距离可以表示为:
d
(
K
A
r
A
,
K
B
r
B
)
=
(
d
(
K
A
,
K
B
)
−
r
A
−
r
B
)
+
(
6
)
d(K_A^{r_A}, K_B^{r_B} ) = (d(K_A, K_B ) - r_A - r_B)+ \kern3em \lparen6\rparen
d(KArA,KBrB)=(d(KA,KB)−rA−rB)+(6)其中+号是代表当值小于0时,值取0。
如果将公式(2)中的子集变成是球面扩展,那么结合公式(4)和公式(6)可得:
d
(
K
A
,
K
B
)
=
m
i
n
{
(
d
i
j
−
r
i
−
r
j
)
+
:
i
∈
I
A
,
j
∈
I
B
}
(
8
)
d(K_A, K_B ) = min \lbrace (d_{ij} - r_i - r_j)+: i \in I_A, j \in I_B \rbrace \kern3em \lparen8\rparen
d(KA,KB)=min{(dij−ri−rj)+:i∈IA,j∈IB}(8)球面扩展可以在不少地方进行应用,像是要加壳的零件等。公式(8)提供了一个便利的计算方式。
接下来是讲当集合需要进行变换时该怎么处理。球面扩展和变换都稍微有点发散,所以这里不展开讲,有需要的话我在后面再进行补充。
在这个小节里,集合X表示m维空间内的紧集,而Y表示m维空间的有限集,即Y中包含有限个顶点。那么集合X的仿射包表示为:
a
f
f
X
=
{
∑
i
=
1
l
λ
i
x
i
,
x
i
∈
X
,
λ
1
+
.
.
.
+
λ
l
=
1
}
(
11
)
aff X= \lbrace \sum_{i = 1}^l \lambda^ix_i,x_i \in X, \lambda^1 + ... + \lambda^l = 1 \rbrace \kern3em \lparen11\rparen
affX={i=1∑lλixi,xi∈X,λ1+...+λl=1}(11)而集合X的凸包为:
c
o
X
=
{
∑
i
=
1
l
λ
i
x
i
,
x
i
∈
X
,
λ
i
⩾
0
,
λ
1
+
.
.
.
+
λ
l
=
1
}
(
12
)
coX= \lbrace \sum_{i = 1}^l \lambda^ix_i,x_i \in X,\lambda^i\geqslant 0 , \lambda^1 + ... + \lambda^l = 1 \rbrace \kern3em \lparen12\rparen
coX={i=1∑lλixi,xi∈X,λi⩾0,λ1+...+λl=1}(12)式(11)和式(12)只差了一个条件:凸包将系数
λ
i
\lambda^i
λi限定为大于0。从上面的定义可以看出,
a
f
f
X
affX
affX是一个线性空间的平移。首先需要明确线性空间这个概念,线性空间也称为向量空间,具体的定义可以参考百度百科:向量空间。为什么说是平移,举个例子,
a
f
f
Y
=
Y
+
{
y
1
}
affY = \bold{Y} + \lbrace y_1 \rbrace
affY=Y+{y1},其中
Y
=
{
y
2
−
y
1
,
y
3
−
y
1
,
.
.
.
,
y
v
−
y
1
}
\bold{Y} = \lbrace y_2-y_1, y_3-y_1, ...,y_v-y_1 \rbrace
Y={y2−y1,y3−y1,...,yv−y1},所以可以知道,这个平移就是说
Y
Y
Y中后v-1个向量组成的向量空间按照向量
y
1
y_1
y1的方向进行平移。如果这时有
d
i
m
a
f
f
Y
=
d
i
m
Y
=
v
−
1
dim \space affY = dim \space \bold{Y} = v-1
dim affY=dim Y=v−1,那么仿射包
a
f
f
Y
affY
affY称为仿射无关(affinely independent)也就是说此时
Y
\bold{Y}
Y中的向量线性无关。否则,仿射包
a
f
f
Y
affY
affY称为仿射相关,此时
Y
\bold{Y}
Y中的向量线性相关,那么肯定存在
Y
Y
Y的子集
Y
ˉ
\bar{Y}
Yˉ使得
a
f
f
Y
ˉ
=
a
f
f
Y
aff\bar{Y} = affY
affYˉ=affY,因为这个时候
Y
\bold{Y}
Y中最多只要v-2个向量即可满足条件。
然后由线性相关的概念可以知道,式(11)和式(12)中的
l
l
l最大值是这些向量所在的线性空间中的维度再加一,例如二维空间需要三个点才能组成面去覆盖二维的凸包,两个点就只能是线;三维空间需要4个点组成4面体才能覆盖三维的凸包,三个点就只能是面。严格的证明可以查看Caratheodory theorem的证明过程。
定义向量空间
X
\bold{X}
X到原点最近的点为
v
(
X
)
v(\bold{X})
v(X),则
v
(
X
)
v(\bold{X})
v(X)的长度的计算公式如下:
v
(
X
)
∈
X
,
∣
v
(
X
)
∣
=
m
i
n
{
∣
x
∣
:
x
∈
X
}
(
13
)
v(\bold{X}) \in \bold{X}, |v(\bold{X})| = min\lbrace |x|: x \in \bold{X}\rbrace \kern3em \lparen13\rparen
v(X)∈X,∣v(X)∣=min{∣x∣:x∈X}(13)一般来说
v
(
X
)
v(\bold{X})
v(X)可能会存在多个点,但是如果X是凸的,那么这个点是唯一的,那么结合式(12)可以得到:
v
(
c
o
X
)
=
∑
i
=
1
l
λ
i
x
i
,
x
i
∈
X
,
λ
i
⩾
0
,
λ
1
+
.
.
.
+
λ
l
=
1
(
14
)
v(coX)= \sum_{i = 1}^l \lambda^ix_i,x_i \in X,\lambda^i\geqslant 0 , \lambda^1 + ... + \lambda^l = 1 \kern3em \lparen14\rparen
v(coX)=i=1∑lλixi,xi∈X,λi⩾0,λ1+...+λl=1(14)一般来说,上式中的
λ
i
\lambda^i
λi、
x
i
x_i
xi和
l
l
l都不是唯一的,但是有两点是很重要的,a)如果
v
(
c
o
X
)
=
0
v(coX) = 0
v(coX)=0,那么
l
⩽
m
+
1
l \leqslant m+1
l⩽m+1(m为向量空间的维度),这是因为原点落在凸包内,结合Caratheodory theorem可以知道结论成立;如果
v
(
c
o
X
)
≠
0
v(coX) \not= 0
v(coX)=0,那么
l
⩽
m
l \leqslant m
l⩽m,因为这个时候原点在凸包之外,那么离原点最近的点一定是落在超平面(凸包的“边”)上。b)
{
x
1
,
x
2
,
.
.
.
,
x
l
}
\lbrace x_1, x_2, ...,x_l \rbrace
{x1,x2,...,xl}仿射无关,这个结论的证明和Caratheodory theorem的相似
定义向量空间
X
\bold{X}
X内的函数
h
X
(
η
)
:
R
m
→
R
h_X(\eta):R^m \to R
hX(η):Rm→R
h
X
(
η
)
=
m
a
x
{
x
⋅
η
:
x
∈
X
}
(
15
)
h_X(\eta) = max\lbrace x · \eta: x \in \bold{X} \rbrace \kern3em \lparen15\rparen
hX(η)=max{x⋅η:x∈X}(15)这个函数返回获取向量空间内离特定向量最远的点。然后将式(15)改写成:
h
X
(
η
)
=
s
X
(
η
)
⋅
η
,
s
X
(
η
)
∈
X
(
16
)
h_X(\eta) = s_X(\eta) ·\eta,s_X(\eta) \in \bold{X} \kern3em \lparen16\rparen
hX(η)=sX(η)⋅η,sX(η)∈X(16)容易证明
h
X
=
h
c
o
X
,
s
X
=
s
c
o
X
h_X = h_{coX},s_X = s_{coX}
hX=hcoX,sX=scoX,因为这时候的点一般都是在凸包的顶点上,而这些顶点也必定属于原来的向量空间(凸包的定义),后面有图会体现这点。
对于有限集
Y
Y
Y,则有:
h
c
o
Y
=
h
Y
=
m
a
x
{
y
i
⋅
η
:
i
=
1
,
2
,
.
.
.
,
v
}
s
c
o
Y
=
s
Y
=
y
j
,
y
j
⋅
η
=
h
Y
(
η
)
(
17
)
h_{coY} = h_Y = max\lbrace y_i · \eta: i = 1,2,...,v \rbrace \space s_{coY} = s_Y = y_j, y_j ·\eta = h_Y(\eta)\kern3em \lparen17\rparen
hcoY=hY=max{yi⋅η:i=1,2,...,v} scoY=sY=yj,yj⋅η=hY(η)(17)上面的概念可以用下面这个图来进行理解:
我认为上面这个图还是比较清晰的,主要是注意各个符号的定义即可。
接下来我们返回公式(4),根据上面提到的概念去求出
d
i
j
d_{ij}
dij,为了简便,设
i
=
1
,
j
=
2
i = 1,j = 2
i=1,j=2。根据公式(4)有:
d
12
=
m
i
n
{
∣
z
∣
:
z
∈
K
}
=
∣
v
(
K
)
∣
,
K
=
K
1
−
K
2
(
18
)
d_{12} = min\lbrace |z|: z \in K \rbrace = |v(K)|, K = K_1 - K_2\kern3em \lparen18\rparen
d12=min{∣z∣:z∈K}=∣v(K)∣,K=K1−K2(18)要求
d
i
j
d_{ij}
dij,首先要求出
h
K
h_K
hK和
s
K
s_K
sK,公式如下:
h
K
(
η
)
=
h
K
1
(
η
)
+
h
K
2
(
−
η
)
,
s
K
(
η
)
=
s
K
1
(
η
)
−
s
K
2
(
−
η
)
(
21
)
h_K(\eta) = h_{K1}(\eta) + h_{K2}(-\eta), s_K(\eta) = s_{K1}(\eta) - s_{K2}(-\eta)\kern3em \lparen21\rparen
hK(η)=hK1(η)+hK2(−η),sK(η)=sK1(η)−sK2(−η)(21)直接这么看有点抽象,用文字描述就是:
h
K
(
η
)
h_K(\eta)
hK(η)等于K1沿着
η
\eta
η方向最长的投影距离减去K2沿着
η
\eta
η方向最短的投影距离,减是因为
h
K
2
(
−
η
)
h_{K2}(-\eta)
hK2(−η) =
−
h
K
2
(
η
)
-h_{K2}(\eta)
−hK2(η)。通过选取不同的
η
\eta
η可以得到不同的点,如果这些点的凸包包含原点,那么说明K1和K2相交(说明K1和K2存在相同的点)。
现在最关键的问题就是如何有效地选取
η
\eta
η,这一块将在第二部分中解决。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。