牵着老婆满街逛

严以律己,宽以待人. 三思而后行.
GMail/GTalk: yanglinbo#google.com;
MSN/Email: tx7do#yahoo.com.cn;
QQ: 3 0 3 3 9 6 9 2 0 .

基于冲量的刚体碰撞运动

来源:http://www.vbgamedev.com/AI/Impulsive.htm

基于冲量的刚体碰撞运动

 

原作者:

Katsuaki Kawachi ,Hiromasa Suzuki, Fumihiko Kimura,J¨org Sauer,Elmar,Sch omer

整理,编写代码:  ZH1110

 

我们在模拟中通常会遇到三种接触情况:

1.双侧的强制约束(Bilateral Constraints),约束始终保持,以前所研究过的是其中的一种方法.

2.瞬间非持久接触(non-permanent permanent contacts),如锻铁、打桩等,可称为碰撞。其特点是在很短的时间间隔内物体的速度发生突然的变化,所以我们很难直接计算其受力大小,而要通过碰撞前后速度变化的规律入手。在这一章我们主要讨论基于冲量的两刚体碰撞运动。

3.持久接触(permanent contacts)第一种的特殊情况.运动着的物体,突然对其施加约束,物体的速度也会发生突变。但在一定条件下约束会消失.他是基于约束(Constraint-based)的

图1,接触的三种情况

 

本节将根据动力学的基本原理对碰撞现象进行描述,讨论其的基本规律,及计算。

 

基本的冲突碰撞

 

一.简化模型的基本的假设:

1.刚体是坚硬的不会因碰撞发生变形

2.对象是多边形

3.摩擦计算基于库仑定律

我们使用下面的符号来表示用到的物理量:(粗体-矢量,常规-标量)

ma ,mb      

对象a,b的质量

Ia ,Ib      

惯性矩, 转动惯量

uA ,uB      

在碰撞前物体A,B中心线速度矢量

uA',uB'   

在碰撞以后物体A,B中心线速度矢量

ωA B     

碰撞前角速度

ωA',ωB'

碰撞以后角速度 

   

碰撞点

vA ,vB      

在碰撞前撞击点线速度矢量

vA',vB'   

在碰撞以后撞击点线速度矢量

GA ,GB

重心坐标

rA ,rB 

重心坐标到碰撞点的矢量

Pn 

碰撞的垂直冲量(Pn=Pn*N)

   

ra,rb在碰撞过程中不会改变,因为假设刚体在碰撞过程中不发生位置的变化.

写成如下形式:

Va为碰撞前刚体A在碰撞点P的速度,Va'为碰撞后刚体A在碰撞点P的速度

 

 

角速度与线速度变化遵守冲量定理:

通过⑴,⑵方程式,我们合并为:

 

 

 

这个方程除了vA'还有Pn是未知量.注意:后面代码我们是把N提到括号外面,计算冲量Pn的矢量数值的。

 

将后面已知部分化简为一常量矢量CA, 类似的我们可得B物体的简写方程式:

B物体的N是相反的,即-N.

 

利用Va,Vb的的相对速度Vn,可以判断是否发生碰撞,如果Vn < 0意味着发生碰撞,如果Vn = 0意味着发生接触,如果Vn > 0意味着发生分离.Vn的定义如下:

和并后个方程式可得碰撞以后的相对速度V'n

如果有n个碰撞点这个方程可扩展为:

⑺ (本章暂不讨论多个碰撞点同时发生的情况)

 

为了计算P,定义一个恢复因数ξ,(牛顿认为碰撞前后相对速度的比为此常数,且该常数与碰撞物体的材料性质有关,与物体的形状、大小与碰撞前的速度无关。)这个重要公式为:

它表明:如果发生碰撞( Pn<>0 ),那么方程就变为

 Vn'=-ξVn

 

计算刚体碰撞运动的一般过程:

1.利用碰撞检测技术检测发生碰撞的二刚体及碰撞点P,碰撞的垂直方向N

2.使用公式计算相对速度Vn.如果Vn>=0,表示两物体处于分离,不再进行计算退出. 使用公式⑼计算相对速度Vn'.

3.使用公式⑶,⑷计算常量Ca,Cb(如果是地面,可将其看做一个质量很大的刚体,也可单独处理)

4.使用公式计算碰撞的垂直冲量Pn

5.将Pn代入⑵即可得到二刚体碰撞后的状态.

代码如下:

Private Sub process_collision(Boxa As box, Boxb As box, collpos As D3DVECTOR, colN As D3DVECTOR, extra As Single)
'开始正冲量的计算
Dim cl As collision
cl.N = colN  ' 碰撞的垂直方向
cl.Ra = Subtract(collpos, Boxa.pos)'重心坐标到碰撞点的矢量
cl.Rb = Subtract(collpos, Boxb.pos)
cl.Va = Add(cross(Boxa.Vang, cl.Ra), Boxa.v) ' v'= v +ω×R
cl.Vb = Add(cross(Boxb.Vang, cl.Rb), Boxb.v)
 cl.Vn = Dot(cl.N, cl.Va) - Dot(cl.N, cl.Vb) - 0.2 * extra '相对垂直速度, 另外副加微小冲量

cl.Vn2 = -0.4 * cl.Vn '垂直相对速度(碰撞后),0.4是恢复因数

If cl.Vn >= 0 Then Exit Sub

'计算Ca  Ca = 1/m+((Ra×N)/Iz×Ra)N Cb = 1/m+((Rb×N)/Iz×Rb)N
cl.Ca = 1 / Boxa.m + Dot(cross(VScale(cross(cl.Ra, cl.N), 1 / Boxa.Iz), cl.Ra), cl.N)
cl.Cb = 1 / Boxb.m + Dot(cross(VScale(cross(cl.Rb, cl.N), 1 / Boxb.Iz), cl.Rb), cl.N)

D3DXVec3Scale cl.Pn, cl.N, ((cl.Vn2 - cl.Vn) / (cl.Ca + cl.Cb))
applyimpulse Boxa, cl.Pn, collpos '应用正冲量
applyimpulse Boxb, VScale(cl.Pn, -1), collpos
...
End Sub

摩擦冲量

既然碰撞的正方向可以应用冲量方程,那么在与之相垂直的方向(摩擦力方向)也可用此方程,只是后面的判断方法不同.

如果2个对象接触并滑行,摩擦力会一直作用于滑行点上,同样的如果发生碰撞,正冲量与摩擦冲量也同时工作,我们描述摩擦产生的冲量为摩擦冲量.

如果摩擦力做工,相切的摩擦冲量将要运做,(t是单位矢量相切于碰撞的边,它的方向可通过P的的速度判断.)如图:

这种情况,相切的速度与冲量关系可以写成类似于方程⑶的形式,:

 

在碰撞期间的摩擦力

在无摩擦的系统下,正接触力fn(t)在[t0,t1]段间持续的作用于2刚体上,因此P点的正冲量为:

现在假设在P点的速度在碰撞开始和期间始终不为0,等量摩擦力ft(t)持续的作用,P点的摩擦量冲为:

(11)

假设在P点碰撞期速度变成了0,摩擦力顶多保持在静摩擦状态,摩擦量冲被限制在:

(12)

 

从上面的推断我们可以推断摩擦冲量的计算过程:

1.根据式⑼与式(11)的摩擦冲量都计算出来

2.如果前者小于后者表示动摩擦力不能一直维持到碰撞结束,实际摩擦冲量为前者,反之亦然.


'开始摩擦冲量的计算
Dim clnew As collision '已经改变的碰撞

...
Vr_all = Subtract(clnew.Va, clnew.Vb)

clnew.tangent_vel = Subtract(Vr_all, VScale(clnew.N, Dot(Vr_all, clnew.N)))'tangent_vel=Va-((Va·N-Vb·N)*N) '相切的速度
clnew.tangent_speed = VLength(clnew.tangent_vel) '相切的速度标量
If clnew.tangent_speed > 0 Then
Dim T As D3DVECTOR
D3DXVec3Scale T, clnew.tangent_vel, -1 / clnew.tangent_speed
clnew.Ca = 1 / Boxa.m + D3DXVec3Dot(T, cross(VScale(cross(clnew.Ra, T), 1 / Boxa.Iz), clnew.Ra))'Ca = 1/m+((Ra×T)/Iz×Ra)T
clnew.Cb = 1 / Boxb.m + D3DXVec3Dot(T, cross(VScale(cross(clnew.Rb, T), 1 / Boxb.Iz), clnew.Ra))
clnew.C = clnew.Ca + clnew.Cb

If clnew.C > 0 Then
Const friction = 0.5 '动摩擦系数
Dim Ptt As Single '临时摩擦冲量
Ptt = clnew.tangent_speed / clnew.C
If Ptt < friction * VLength(cl.Pn) Then '动静摩擦判断
clnew.Pt = Ptt
Else
clnew.Pt = friction * VLength(cl.Pn)
End If

applyimpulse Boxa, VScale(T, clnew.Pt), collpos  '应用摩擦冲量
applyimpulse Boxb, VScale(T, -clnew.Pt), collpos
End If
End If

刺透处理

为防止一物体刺穿另一物体,需要对刺穿进行处理.一个方法是检测时计算出刺入的深度,后在碰撞副加一微小冲量,使其分离.简单的考虑到一次就对半分离过于突然,不能取得最好的效果,所以每次以按一比例分离

 

 

 

另一个简单方法是直接修改刚体的位置:
Boxa.pos = Add(VScale(colN, extra * 0.2), Boxa.pos)
Boxb.pos = Add(VScale(colN, -extra * 0.2), Boxb.pos)

目前流行的物理引擎都是通过高级碰撞检测技术即未发生刺穿前�

posted on 2008-01-15 16:41 杨粼波 阅读(653) 评论(0)  编辑 收藏 引用