1. 碰撞检测系统
物理世界
形状:
- 相交、
- 接触(分离矢量,沿该矢量运动就能高效脱离碰撞妆容)、
- 凸(由形状内发射的光线不会穿越形状两次以上)
原型:
- 球体、
- 胶囊体、
- 轴对其包围盒AABB、
- 定向包围盒OBB、
- 离散定向多胞形discrete oriented polytope DOP、
- 任意凸体积、
- 多边形汤(碰撞引擎必须和每个三角形测试)、
- 复合形状
碰撞测试:
- 点和球体相交
- 球体和球体相交
- 分离轴定理:凸形状于该轴(分离轴)上的投影不重叠,能确定两个形状不相交。分离两个物体的轴/面称为分离线/面。三维空间中,分离轴仍然是个轴,分离线变成分离面。可以把形状逐一投影到各个潜在分离轴,并检查投影区间是否相交
- AABB相交:分离轴定理。三个轴x,y,z。只有在三个轴都重叠,才是相交的。
- 检测凸碰撞:GJK算法。依赖闵可夫斯基差:把A中的所有点与B中的所有点都成对相减,得到的集合就是闵可夫斯基差。当且仅当两个形状相交,闵可夫斯基差包含原点。GJK尝试在闵科夫斯基的凸包内,尝试找出一个包含原点的四面体。若找到,则相交。
- 运动物体间的碰撞:
-
- 离散的静态碰撞;
- sweep shape扫琼形状做静态测试(结果不准确);
- 连续碰撞检测continuous collision detection CCD,求出最早的冲击时间TOI
性能优化:
- 利用时间一致性避免每帧重新计算一些类型的信息
- 空间划分
- 粗略阶段,中间阶段,精确阶段:先AABB测试哪些物体会碰撞;再用符合形状的逼近包围体检测;最终进行青雀的碰撞检测
- 扫琼裁剪:sweep and prune,对各个膨胀提的AABB的最小,最大坐标再三个主轴上排序,然后通过遍历改有序表检测AABB之间是否重叠
碰撞查询:
- 光线投射:投射的物体并不存在于碰撞世界,不会影响其他物体。返回一个t值,P = P0 + td
- 形状投射:返回多个接触点。模拟玩家的脚
- Phantom:查询碰撞体是否在其他指定体积里。对于其他碰撞体是透明的,也不参与动力学模拟。
碰撞过滤:决定碰撞体之间的接触是否成立
- 碰撞掩码及碰撞层:掩码
- 碰撞回调:回调函数按自己的条件决定接受或拒绝碰撞
- 碰撞材质:包含碰撞属性,如音效,粒子效果,摩擦系数等等
2. 刚体动力学
6个自由度DOF
线性动力学(质点)
运动方程求解
- 力作为函数:位置、速度、时间等的函数(常微分方程(ordinary differential equation ODE))。类似弹簧
- 解析解:找到闭合式函数,描述所有可能的时间值t的刚体位置(例如抛物线),但是游戏中几乎不可能。
- 常微分方程的数值解的特性:
-
- 收敛性:delta_t趋近于0的时候,近似解趋近镇世界?
- 阶数:误差是O(t^?)
- 稳定性:数值解是否会稳定下来?
- 数值积分:游戏引擎使用数值积分求解运动方程
-
pos(t2) = pos(t1) + v(t1)delta_t
v(t2) = v(t1) + F(t)/m * delta_t
实际是假设在该时间步中,物体速度维持不变。由于位置的斜率就是速度,实际上也能理解为导数的逼近。当delta_t趋近于0的时候是合法的
一阶方法,误差是O(t^2),准确度达到并包括delta_t一次方的泰勒级数
可以仅仅用到加速度就求解位置
pos(t1+delta_t) = 2pos(t1) - pos(t1-delta_t) + F(t1)/m * delta_t^2 + O(t^4)
v(t1+delta_t) = delta_pos / delta_t
pos(t+delta_t)= pos(t1) + v(t1)*delta_t + 0.5a(t1)*delta_+t^2
v(t+0.5delta_t) = v(t1) + 0.5a(t1)*delta_t
求a(t1+delta_t) (假设a仅仅依赖位置,如果依赖速度,则需要先计算速度近似值)
v(t+delta_t) = v(t1) + 0.5a(t1)*delta_t + 0.5a(t2)*delta_t
旋转动力学(刚体)
-
- 转动惯量moment of inertia:改变角速率的难易程度。用I表示
- 力矩torque:用N表示
N=rxF
二维中力矩必然和z轴平行
-
- 二维旋转方程求解:
显示欧拉逼近解:
Ixx,Iyy,Izz是刚体绕三个主轴的转动惯量。如果3个主轴对称,则对角线以外的元素(也叫惯量积)就是0
物理引擎中惯性张量简化为三元素矢量[Ixx, Iyy, Izz]
转动惯量:Izz(惯性张量沿转轴方向的主值)
可以表示为3个欧拉角[theta_x, theta_y, theta_z],但是会有万向节死锁,所以也会用四元数q表示
q=[旋转轴u*sin(0.5 theta), cos(0.5 theta)]
矢量w:绕旋转轴u转角速度标量w=theta' * u
在无力矩情况下角速度能改变:角速度不守恒
但是角动量(angular momentum,表示为L)守恒。
L=[Lx, Ly, Lz]
由于w不守恒,所以不会像线性速度一般,视角速度为一个基本的两。角速度是第二级别的量,在确定了角动量L后才计算出w
N = rxF = Ia = I dw/dt = d(Iw)/dt = dL/dt
不能用二维旋转方程求解的方法求解了
需要直接对L求解
将角速度转化成四元数:w = [wx, wy, wz, 0]
方向q' = 0.5(w*q) =>四元数积
显示欧拉:
3.碰撞响应
如果是完全弹性碰撞,能量损失为0
-
- 无摩擦力下瞬时碰撞的牛顿恢复定律:假设接触点没有摩擦力,冲量必然垂直于表面法线
恢复系数:v2'-v1'=e(v2 - v1)
将两者求解得
根据e求得p^,带入v1 + p^/m1*n 求出v1'
- 惩罚性力:力会在短但有限的时间内产生所需的碰撞响应。就类似一个坚硬的阻尼弹簧。
容易实现及理解,适合低速撞击
4. 摩擦力
静摩擦力
滑动摩擦力
滚动摩擦力
碰撞摩擦力
5. 休眠
将休眠物体移除模拟之外,但是仍然参与碰撞检测
条件:
刚体受到支持
v和角动量低于阈值
总动能(0.5pv+0.5Lw)低于阈值
Havok中有模拟岛:潜在近期会互动的物体组成。模拟岛能独立于其他岛模拟,并以整个岛为单位进入休眠。
6.约束
点对点约束
弹簧约束
铰链约束
活塞约束
平面约束
轮子:无限旋转的铰链+阻尼弹簧加入某种形式的垂直悬挂系统
约束链:特殊群组,内含供求解程序使用的物体连接信息。模拟一长串的刚体信息
布娃娃:刚体用约束互相链接。是由物理系统驱动的程序式动画
富动力约束(powered constraint):外部引擎间接控制布娃娃的平移和定向。力+动画,力改变动画
7.控制运动
引力
施加力:多数引擎设计为每帧调用一次,力的影响也在该帧内
施加力矩:改变速度&角速度;力偶:一样大,方向相反,离质心距离相同的对点上施加。
施加冲量:速度瞬间改变,无穷短时间内的施力
8.游戏对象和刚体:
物理驱动的刚体
游戏驱动的刚体(动画、玩家驱动):可当作含有无穷质量,力和力矩无法改变游戏驱动刚的速度
固定刚体:不参加动力学模拟,只有碰撞的刚体
9.更新模拟
更新游戏驱动刚体
更新phantom
施以力,冲量并调整约束
步进模拟:
对运动方程数值积分,求出次帧物理状态
碰撞检测
碰撞决议
实行约束
更新物理驱动的游戏对象
执行phantom&碰撞投射查询(以回调方式异步查询or使用上一帧的结果同步查询)
渲染
更新策略:
单线程更新
多线程更新:
物理专用线程:可能导致过期的位置信息-race condition-线程同步 or 使用命令队列做线程通信
fork, join:每个模拟岛步进的过程fork成独立的线程,当所有线程完成工作后join结果,主线程继续单线程更新。
作业模型
(图片没法调整大小,扎心了)