球体弹性碰撞模拟

by:zh1110

碰撞检测技术是很多游戏重要的组成部分

首先我们为球和碰撞的平面定义两个类型,计算时使用DX辅助库中向量的相关函数,以达到较佳性能

            

'球的定义
Type ball
pos As D3DVECTOR '位置
v As D3DVECTOR '速度
acc As D3DVECTOR '加速度
bo As Boolean '是否掉落场外
End Type

'自定义平面格式(三角面)
Type shdow
v0 As D3DVECTOR '面法向
v1 As D3DVECTOR '顶点1
v2 As D3DVECTOR '顶点2
v3 As D3DVECTOR '顶点3
d As Single '距圆点距离
End Type

Public ba(20) As ball

球在未与平面发生碰撞时作平抛运动或自由落体运动,位置和速度的物理公式为:

s=vt      v=at

如果我们将系数设置为1,周期为1秒,那么每次计算速度时,只需将速度与加速度简单的向量相加便得到结果,位置的计算也可类似处理

For k = 0 To 20

D3DXVec3Add ba(k).v, ba(k).v, ba(k).acc

D3DXVec3Add ba(k).pos, ba(k).v, ba(k).pos

Next

 

球与墙壁的弹性碰撞

为了产生碰撞,首先必须必须知道球是否撞到了平面,弹性碰撞无能量损失,速度不会减慢但方向改变了,须计算反弹的方向。

1根据物体的运动规律计算物体在将渲染的一帧

2判断物体在前一帧和当前帧时的位置与平面S的关系:如果上一帧在平面前,而当前帧在平面后

因为前后两帧物体在平面的异侧,说明物体穿过了平面S。

d = D3DXVec3Dot(showed(i).v0, ba(j).pos) - showed(i).d '计算当前帧球体中心到平面的距离
D3DXVec3Scale vettore3, ba(j).v, -1  '速度反向
D3DXVec3Add vettore3, vettore3, ba(j).pos '计算前一帧球体中心位置
d2 = D3DXVec3Dot(showed(i).v0, vettore3) - showed(i).d '计算前一帧球体中心到平面的距离

If d < 4 And d2 > 4 Then    '在平面的异侧,4是球体半径

 

 

判断是否在三角形内:

物体在平面的异侧,但这时还不能说物体与三角形发生了碰撞,因为三角形是有边界的,还需进一步判断撞击点是否在三角形三条边范围之内穿过平面:

 


如图,从交点到三角形的三个顶点作向量,计算相领向量的夹角余弦a1,a2,a3,如果夹角余弦和小于-1则点在三角形内部,如果夹角余弦和大于-1则点在三角形外,夹角余弦的计算可通过两个单位向量作点积。

D3DXVec3Scale vettore, showed(i).v0, -d
D3DXVec3Add vettore1, ba(j).pos, vettore  '计算交点
D3DXVec3Subtract v0, vettore1, showed(i).v1  '交点到三个顶点的向量
D3DXVec3Subtract v1, vettore1, showed(i).v2
D3DXVec3Subtract v2, vettore1, showed(i).v3
D3DXVec3Normalize v0, v0  '计算夹角余弦需先单位化向量
D3DXVec3Normalize v1, v1
D3DXVec3Normalize v2, v2
c0 = D3DXVec3Dot(v0, v1)  '计算相领向量的夹角余弦值a1,a2,a3
c1 = D3DXVec3Dot(v1, v2)
c2 = D3DXVec3Dot(v2, v0)

If (c0 + c1 + c2) < -1 Then

 

反弹的计算:

如图,我们将速度分解为平行于平面的分量Vx和投影到平面法向的Vy.  Vy因为受碰撞力反向变成Vy',但速度的大小不变,然后将Vy'与Vx相加就得到碰撞后的速度V'.

D3DXVec3Scale vettore3, showed(i).v0, -d + 4
D3DXVec3Add ba(j).pos, ba(j).pos, vettore3  '重新定义位置

D3DXVec3Cross vettore1, showed(i).v0, ba(j).v  '垂直
D3DXVec3Normalize vettore1, vettore1
D3DXVec3Cross vettore2, showed(i).v0, vettore1  '平行于平面的单位向量
c1 = D3DXVec3Dot(vettore2, ba(j).v)  '计算Vx,Vy的长度
c2 = D3DXVec3Dot(showed(i).v0, ba(j).v)
D3DXVec3Scale vettore2, vettore2, c1    '计算平行于平面的分量Vx
D3DXVec3Scale vettore, showed(i).v0, -c2    '计算投影到法向的Vy',负数即反向
D3DXVec3Add ba(j).v, vettore, vettore2     '将Vy'与Vx相加就得到碰撞后的速度V'
D3DXVec3Scale ba(j).v, ba(j).v, accd    '我们可以设置一反弹率accd(默认0.97,能量损失)

 

球体间的碰撞:

球体间的碰撞与球与墙壁的碰撞类似,只是碰撞两球的速度进行了交换(碰撞的方向上)。

 

文件下载