高速旋转球体的物理动画模拟(虚幻4实现)

GitHub仓库 地址

前几天突发奇想,虚幻4里有没有办法模拟出乒乓球在真实世界的运动规律呢(比如下旋的回弹,上旋加速等)?

据我自己非常不深入的了解,引擎在碰撞时应当是没有考虑角速度的影响的,那能否自己实现一个呢?

话不多说,直接开始正题。

高速旋转球体角速度对运动的影响

先来进行一些简单情景的受力分析。

  • 考虑从左向右运动的球体,在运动时从观察者方向看是顺时针旋转的(乒乓球等球类运动里,对应的是上旋)。此时,如果球与地面接触,那么角速度对球底部接触点会产生一个向左的线速度,质心向右运动,有向右的速度。接触地面点合速度的方向取决于角速度和线速度哪个更大,因此滑动摩擦方向可能向左也可能向右。打得好的上旋球角速度的影响更大,此时摩擦力是向前的,这导致碰撞后质心水平速度会更大,看起来运动得更快。
  • 仍然考虑从左向右运动的物体,但此时逆时针旋转(对应球类运动的下旋)。此时角速度对球底部产生一个向右的线速度,质心速度也向右。此时合速度必然向右,于是滑动摩擦向左。于是下旋球在质心速度较低的时候,可能会因为摩擦力的冲量向左回弹。

于是我们可以想到:

  • 球与桌面接触时的受力可以分解为两部分,第一部分是球与桌面撞击产生弹性形变的支持力,第二部分是接触点速度反向的摩擦力。
  • 球是均匀的,支持力过质心,不会影响角速度,且不会影响水平方向速度。
  • 摩擦力作用点不在质心,产生力矩,影响角速度和水平方向速度,但不会影响竖直方向速度。
  • 如果碰撞过程完全没有能量损失,支持力的冲量正好使得球竖直方向的速度大小不变,方向相反。

对碰撞模型的一些假设

因为是模拟物理动画,当然不可能做到100%还原如此复杂的情景的,所以我对碰撞过程做了一些假设,简化模型的同时让模拟结果看起来合理:

  • 没有空气阻力,即不考虑马格努斯效应等对运动的影响(之后可能会加上);
  • 在与地面、墙面碰撞过程中,仅正碰方向有10%的速度损耗;
  • 竖直方向速度,低于某个值的时候直接置0(因为模拟时一步的时间步长是有限值,弹跳时间间隔低于一步的话,一直模拟会出现难以停止的情况);
  • 碰撞过程不考虑滑动摩擦以外的摩擦力。

理论论证

非常感谢在sysu学物理的W同学为我检查证明过程,以及X同学提供的论文!

因为接触桌面时间很短,忽略重力的影响,在0至T时间段支持力对球的冲量大小为
I_N = \int_0^T N(t)\,{\rm d} t,
设摩擦因数为mu,摩擦力的冲量大小为(这里有个漏洞,将在后面说明
I_f = \int _0^T \mu N(t)\,{\rm d}t = \mu I_N.
假设碰撞前后竖直方向上质心速度大小为vz,即竖直方向速度变化量为2vz,球质量为m,正碰后速度比为xi(=0.9),则质心水平方向速度的变化量的大小为
I_N = m \Delta v_z = (1+\xi)mv_z,

\Delta v = \frac{I_f}{m}=\frac{2\mu m v_z}{m}=(1+\xi) \mu v_z.
设球半径为r,转动惯量J,则角速度的变化量大小为
\Delta \omega = \int_0^T \frac{fr}{J}\,{\rm d}t=\frac{I_f r}J = \frac{(1+\xi)\mu m v_z r}J.
方向是摩擦力f与接触面法线方向叉乘。

同理,在与其他表面碰撞时模型是完全相同的(忽略重力),只需要将vz改为对应墙面/接触面法线方向的速度即可。

实现

实际计算的时候,每tick更新一次速度、角速度和位置。每tick(时长t0)判断碰撞时,计算出发生碰撞的点以及发生碰撞的时间t1,只记录下最早碰撞的位置即可。如果没有碰撞,用速度更新位置后用重力加速度更新速度;如果发生了碰撞,那么将球移动到碰撞点,更新碰撞结果后再按当前速度无碰撞仅受重力加速度影响运动t1-t0时间。如果碰到地面且竖直方向速度vz过小,将vz置0并让球进入滚动状态。滚动部分分为滑动摩擦滚动和纯滚动,纯滚动时摩擦因数需要设置较小的值。

上述论证的漏洞与修复

实际实现后,会发现一个现象:某些参数下的下旋球,会往回弹一次,然后又向前弹。这与观察到的现象是明显不符的(感谢zju的L同学的实验视频与论证!一些弹性较好的材质确实是可以很容易出现这样的反复回弹的,我看到弹力球两次反复回弹的时候确实惊呆了。乒乓球似乎也可以,有可能是空气流动或其他作用力导致的。我主要讨论的是近似刚体的运动,所以暂时不考虑如此复杂的情形)。

对角速度进行了一些调试分析,我发现了问题的所在:在第二次回弹的时候,角速度和水平速度的方向均反向了。这时我参考了X同学发给我的论文,我注意到了一个非常严重的漏洞:摩擦力是纯耗散的,在接触点合速度归0后,滑动摩擦并不存在。也就是说,滑动摩擦力不是在0至T时刻持续存在的,上面的积分并不成立,即
I_f \le \mu I_N.
于是,需要对上述模型做一些修正。考虑摩擦力f导致的接触点线速度改变量,实际上等于
\Delta v+r\Delta \omega = \frac 1m I_f +\frac{r^2}J I_f = \left(\frac 1m + \frac{r^2}J\right)I_f.
以球与地面碰撞为例,我们有限制
\Delta v+r\Delta \omega \le |{\bf v}_{xy}+r{\bf n\times \omega} |,
式子的右边是碰撞发生前瞬间的合速度,vxy是水平方向质心速度,n为法线。这意味着
I_f = \min\left(\mu I_N, \frac{mJ}{J+mr^2}|{\bf v}_{xy}+r{\bf n\times \omega} |\right).
修正后的速度、角速度更新公式:
\Delta v =\min\left((1+\xi)\mu v_z, \frac J{J+mr^2}|{\bf v}_{xy}+r{\bf n\times \omega} |\right),

\Delta \omega =mr \min\left((1+\xi)\frac{\mu}J v_z, \frac{1}{J+mr^2}|{\bf v}_{xy}+r{\bf n\times \omega} |\right).

结果展示

之后在虚幻引擎里写一些蓝图事件,用一个箭头表示出角速度的大小和方向,这一个toy project就算完成了。做出的下旋球模拟示例如下。

该toy可以展示任意初始角速度和初始质心速度,匀质球体在无空气影响下的运动和碰撞。

(非物理专业,只是一个一天时间内与朋友讨论完成的玩具虚幻项目,如果有一些论证错误和漏洞,请您务必留言告诉我,谢谢!)