我正在编写自己的基本物理引擎,但现在遇到了一个我无法解决的问题。可能是因为我不知道如何用谷歌搜索这个问题。
所以这是我的问题。我希望这张图片可以解释它:
我有两个对象。灰色的是固定不动的,绿色的是从上面掉下来的。绿色物体具有三个向量:力、加速度和速度。它与固定的灰色物体发生碰撞。
真正的问题是如何在绿色物体掉落时获得旋转?
我正在编写自己的基本物理引擎,但现在遇到了一个我无法解决的问题。可能是因为我不知道如何用谷歌搜索这个问题。
所以这是我的问题。我希望这张图片可以解释它:
我有两个对象。灰色的是固定不动的,绿色的是从上面掉下来的。绿色物体具有三个向量:力、加速度和速度。它与固定的灰色物体发生碰撞。
真正的问题是如何在绿色物体掉落时获得旋转?
听起来您可能不了解刚体动力学背后的基础物理学。我这么说只是因为你在谈论这类问题时没有提到任何常用的术语。您需要将方向和角速度的概念(位置和线速度的旋转模拟)引入系统中的每个动态体,并计算各种中间量,如惯性矩、角加速度和扭矩。
也许最好的介绍性参考是Chris Hecker为 Game Developer Magazine 撰写的系列文章。假设您已经解决了非旋转动力学(第 1 部分中介绍)和碰撞检测(本系列未介绍),您应该从第 2 部分开始并继续第 3 部分。它们将为您提供坚实的物理学基础和实现旋转碰撞响应所需的数学。
当对象发生碰撞时,您按如下所述执行一次。
让我们称绿色矩形为“a”,另一个为“b”。
首先你需要矩形“旋转质量”,惯性质量。
ai = 4/3 * 宽度 * 高度 * (宽度^2 + 高度^2) * a.密度
然后你需要从矩形的质心(所有角的平均位置)指向接触位置(矩形碰撞的地方)的向量,我们称之为“r”。
然后你需要找到碰撞法线。该法线是从 b 施加到 a 的脉冲的方向。法线是长度为 1 个单位的向量。在您的示例中,法线可能会向上。让我们将法线向量称为“n”。
现在你需要 a 上接触点的速度。如果 a 不旋转,则公式为:
vp = a.vel
如果 a 正在旋转,则公式为:
vp = a.vel + cross(a.r_vel, r)
a.r_vel 是以弧度给出的 a 的旋转速度,正方向为逆时针方向。
cross() 表示叉积,函数为:
交叉 (v,i) = [-i * vy , i * vx]
扩展公式为:
vp = av + [-r * a.r_vel.y , r * a.r_vel.x]
现在您需要计算对象是否相互移动。将 vp 投影到 n 上。
vp_p = 点(vp,n)
点 (v1, v2) = v1.x * v2.x + v1.y * v2.y
vp_p 是一个标量(一个值,而不是一个向量)。
如果 vp_p 为负,则对象正在相互靠近,如果 > 0,则它们正在分开。
现在你需要计算阻止a移动到b的冲动,冲动是:
j = -vp_p / ( 1/a.mass + cross(r,n)^2 / ai )
两个向量之间的叉积是:
交叉(v1,v2)= v1.x * v2.y - v1.y * v2.x
它返回一个标量。
将冲量与法线相乘得到冲量向量:
jn = j * n
现在您需要将脉冲应用于:
a.new_vel = a.old_vel + jn / a.mass;
a.new_r_vel = a.old_r_vel + cross(r,jn) / ai;
如果您希望碰撞完全有弹性,则必须将冲量乘以 2。让我们将此乘数称为“e”。e 需要介于 1 和 2 之间。1 表示没有能量守恒,2 表示所有能量都守恒。
var vp = a.vel + cross(a.r_vel, r);
var vp_p = dot(vp,n); // negative val = moving towards each other
if (vp_p >= 0) { // do they move apart?
return false;
}
// normal impulse
var j = - e * vp_p / (
1/a.mass + cross(r,n)^2 / a.i
);
var jn = j * n;
//
a.vel = a.vel + jn / a.mass;
a.r_vel = a.r_vel + cross(r,jn) / a.i;
如果 b 不是静态的,算法会略有不同:
ar = 从 a 的质心指向接触位置的向量
var vp = a.vel + cross(a.r_vel, a.r) - b.vel - cross(b.r_vel, b.r);
var vp_p = dot(vp,n); // negative val = moving towards each other
if (vp_p >= 0) { // do they move apart?
return false;
}
// normal impulse
var j = - e * vp_p / (
1/a.mass + cross(a.r,n)^2 / a.i +
1/b.mass + cross(b.r,n)^2 / b.i
);
var jn = j * n;
//
a.vel = a.vel + jp / a.mass;
a.r_vel = a.r_vel + cross(a.r,jn) / a.i;
b.vel = b.vel - jp / b.mass;
b.r_vel = b.r_vel - cross(b.r,jn) / b.i;
公式如何工作/来源: