第三章:不能再简单的世界
在真正开始编写之前,先回顾一下初中学过的经典物理的知识,OK,闭上眼睛想三分钟,嗯,动量守恒,摩擦系数,胡克定律,弹性碰撞。。。是不是突然想到了很多,但是并不系统,这里就简单的,系统的总结一下游戏中需要物理学知识(更详细的推荐《游戏开发物理学》)。
在物理世界的仿真中,一般我们至少要进行以下三种现象的仿真。
1.线性运动:包括定加速,不定加速运动,考虑摩擦力,压差,重力,阻尼,浮力等。
2.旋转:要计算角速度,力矩,转动惯量等。
3.弹性碰撞:包括完全弹性碰撞,非完全弹性碰撞,完全非弹性碰撞等。
关于二维和三维坐标系的知识就不做介绍,关于公式的推导也都省略了,只给出实用的结果公式。
注:以下公式中:*表示乘法,也是点积;×表示叉乘(外积),^表示幂。
第一节:线性运动
为了仿真物体的线性运动,需要知道计算物体的质量,速度,如果要考虑摩擦力,还需要物体的摩擦系数,要计算重力,需要引力常数等。
质心
对于组合物体,如飞船由引擎,人员,船身等各个部分组成,而不同部分的重量不同,在计算物体线性运动时,施加在物体上的力,都看做是施加在物体质心上的,所以在计算物体运动之前要先算出物体的质心。
Mc = ∑(mc_i * m_i ) / m
Mc是物体合并后的质心,mc_i是物体中每个质点的坐标(二维或三维空间下的向量),m_i是每个质点的质量,m是物体的总质量。
牛顿第二定律
这是计算线性运动的基本定律,即根据作用在物体质心上的合力计算物体的加速度:
∑F = m*a
m是物体的质量,a是在力作用下的加速度,∑F是施加在质心的合力,F和a都是向量。一般把F分解为沿着空间坐标轴的分量计算沿着不同坐标轴的加速度。如果运动过程中∑F不变,则成为定加速运动,如果∑F再运动中变换就是变加速运动。
定加速运动
物体的及时速度 v是由上一时刻速度v'和加速度a 决定的,
v = v' + a * t
这个就不解释了,同理:
s = v * t + 1/2 * a * t^2
变加速运动
因为物体在运动中会受到阻力(这里说的不同于摩擦力),阻力一般与速度的平方成正比,由此可知阻力引起的反加速度也与速度的平方成反比:
a = -k * v^2
a既是阻力引起的加速度,k为常数而负号表示方向相反。对于此类变加速运动,及时速度为:
v = v' / (1 + v' * k * t)
v'是上一时刻的速度,t是经过的时间。而距离公式为:
s =ln(1 + v' * k * t) / k
其中v和a都是向量,ln是自然对数,在二维和三维空间中可以分别分解为坐标轴的不同分量进行计算。
各种力
说了这么多可能还有人有疑问,各种合力都是那些力啊,首先说一下重力,重力是万有引力的特殊形式,引力公式如下:
Fa = G * m1 * m2 / r^2
G是万有引力常数,m1与m2是两个物体的质量,r是物体间的距离。根据牛顿第二定律和地球的质量以及引力常数可以求得,海平面附近在地球引力作用下物体的加速度为9.8m/s^2。
然后就是物体的摩擦力,物体的摩擦力比较复杂,既是两个物体在压力作用下,某个接触面阻碍相互运动的力。摩擦力公式为:
Ff = p * N
其中N为垂直于接触面的压力,p为接触面的摩擦系数。摩擦系数分为静摩系数和动摩擦系数,即物体在静止时的摩擦系数和运动时。静摩擦系数一般大于动摩擦系数,即是说物体由静止转向运动要克服一个较大的力,当物体处于运动状态则收到的摩擦力较小。摩擦系数是对于两个接触面统一来说的,而一般在游戏中通过分别设置两个物体的摩擦系数来仿真。
之前变加速运动时提到的流动阻力,比如位于两种流体间运动的物体,比如船在空气和水面间,收到水波的影响。流动阻力一般和速度的平方成反比
F = C * v^2
C为阻力系数。还有就是物体在液体中的浮力,由液体的压强差决定:
F = F_b - F_t
F_b = P * A = p * g * h * A
浮力既是物体在不同高度受到的压力差如(F_b,F_t)决定的,而压力是压强P乘以接触面积A,液体压强P是液体深度h乘以密度p再乘以重力加速度g。
在仿真过程中还经常遇到弹力的例子,根据胡克定律,弹力是由于物体伸长或缩短而受到的力:
Fs = ks * ( L - r )
ks是弹力系数,L是物体伸长或缩短的长度,r是原先的长度。另外阻尼常与弹力联合使用,阻尼是抵消相对速度的力,
Fd = kd * ( v - v')
kd是阻尼常数。两个公式合并后为:
F = -( ks * ( L - r ) + kd * ( ( v - v' ) * L ) / s ) * L / s
L为弹簧阻尼单元的长度向量,而s是L的长度。利用弹簧阻尼单元可以用来仿真布料,将布料网格每个交叉点看做粒子,与周围粒子靠弹簧/阻尼公式连接,这样每个粒子在重力,风等的作用下,网格就呈布料的特性。
第二节 旋转
介绍完线性运动,基本上大部分的力和定理都明白了,但是对于刚体的仿真,在力作用到刚体上时,根据作用点的不同不但会产生线性运动,还会产生转动。计算产生的转动需要的量有力矩和转动惯量。
转动惯量
转动惯量是物体绕轴旋转,其质量呈辐射分布的度量,用于计算物体的旋转。物体到某一轴的转动惯量计算公式为,其各个质点到该轴距离乘积的积分,如三维空间下,对x,y,z轴的转动惯量公式:
I_x = ∫(y^2+z^2)dm
I_y = ∫(x^2+z^2)dm
I_z = ∫(y^2+x^2)dm
根据转动惯量的公式可知,物体相对于其他平行轴的转动惯量为:
I = I_o + m*d^2
其中m是物体自身的质量,d是两平行轴间的距离,I_o是物体相对于自身某转动轴的转动惯量,。当md^2较大时,I_o可以忽略不计。
而对于一些规则物体,其相对于自身转动轴的转动惯量都有可直接计算的公式,如圆柱体,长方体,球体(这也是为什么大多数物理引擎的刚体都支持这些形状的原因之一)。对于这些公式就不再列举了,可以随意查到,有兴趣也可以自己积分一下。
力矩
如果力可以使物体转动,说明作用在物体上的力的力矩不为零,力矩计算如下:
M_cg = r× F
M_cg为力矩,×是叉乘(外积)。F为施加在某一质点的力,r为该力(向量)的作用线(直线)到质心的距离向量。根据作用力的力矩可以求出物体的转动角加速度的方程。
∑M_cg = I*a
其中I为转动惯量,是张量,在三维空间中是3x3的矩阵。∑M_cg为作用力矩的总和。a为角加速度。角加速度和角速度都是垂直于旋转轴的向量,二维空间中是标量。这样在计算过程中可能要不断地计算转动惯量和其逆矩阵,为了方便计算,将其化为局部坐标,公式为:
∑M_cg = I*(dw/dt)+w×(I*w)
w为角速度,t为时间,这样所有量都化成了局部坐标,除非物体质量或形状发生变化,不然物体的转动惯量是常数。
第三节 碰撞
冲量定律
动量就不介绍了,冲量是碰撞前后动量的变化:
Jf = m * ( v - v' )
Jm = I * ( w - w' )
m是物体质量,I是转动惯量,w,v是碰撞后的角速度与线速度,w',v'是碰撞前的角速度与线速度。Jf是线性冲量,Jm是角冲量。其中角冲量与线冲量的关系为:
Jm = Jf × r
即线冲量作用线与其到重心的距离向量的外积。因为外积满足分配率,由此可知角动量与线动量的关系。
动量守恒定律
动量守恒定律揭示了两个物体m1与m2碰撞前后速度的关系:
m1 * v1 + m2 * v2 = m1 * v1' + m2 * v2'
其中v1,v2是m1,m2碰撞前的线速度,v1',v2'是m1,m2碰撞后的线速度。这里的v是线速度,如果是角速度则不成立。
能量守恒定律
能量守恒定律表示碰撞的两个物体能量不会损失:
m1 * v1^2 + m2 * v2^2 = m1 * v1'^2 + m2 * v2'^2
参数同上,根据这两个公式可以求出两个物体碰撞后的速度。
但是能量守恒定律都是对于完全弹性碰撞而言的,即刚体形状不发生变化,因为物体形状发生变化要消耗能量,能量消耗就不守恒了。为了仿真非完全弹性碰撞给出了弹性恢复公式:
e = (v1 - v2) / (v1' - v2')
e是恢复系数,根据碰撞物体不同而不同。其中当e=0是完全非弹性碰撞,即碰撞后两个物体合为一个,e=1是完全弹性碰撞即能量守恒。配合动量守恒公式,就可以求出碰撞后两物体的速度了。
最后在计算一些复杂运动物体时,物体碰撞面的线速度是由当前物体的线速度和旋转的角速度组成的,线速度v与角速度w的转换如下:
v = w × r
即线速度是角速度与接触点到质心向量的外积。这里v,w,r都是空间中的向量。
介绍完基本的物理定律,在系统中计算流程一般如下:
1.初始化时计算物体重心,转动惯量
2.在循环仿真中,先计算作用力的合力,力矩,如摩擦力,阻力,重力
3.根据动量定律,速度方程等更新物体位置
4.如果发生碰撞,根据动量守恒定律,角速度与线速度的关系,建立方程即可求得碰撞后的物体状态
这样游戏开发中遇到的基本物理学知识就差不多了。以上的不少变量都是向量,在二维和三维的系统中处理时要用到向量和矩阵运算,有关物体平移,旋转,缩放的操作之后再介绍。