所以这就是我的问题。希望这张图片可以解释清楚: 碰撞响应 我有两个物体。灰色的物体固定不动,绿色的物体从顶部落下。 绿色物体有三个向量:一个力、加速度和速度。它与固定的灰色物体发生碰撞。
真正的问题是,当绿色物体掉落时,我如何得到它的旋转?
看起来你可能没有理解刚体动力学基础物理原理。我这么说是因为你在谈论这类问题时没有提到常用的术语。你需要为系统中的每个动态体引入方向和角速度(位置和线速度的旋转对应物),并计算各种中间量,例如惯性矩、角加速度和力矩。
也许最好的入门参考资料是Chris Hecker在Game Developer Magazine上发表的系列文章。假设你已经解决了非旋转动力学(第1部分介绍)和碰撞检测(本系列不涉及)问题,你应该从第2部分开始,然后继续第3部分。它们将为你实现旋转碰撞响应所需的物理和数学基础打下坚实基础。
当物体碰撞时,根据以下步骤进行操作:
我们将绿色矩形称为“a”,另一个矩形称为“b”。
首先需要确定矩形的“旋转质量”,也就是惯性质量。
a.i = 4/3 * width * height * (width^2 + height^2) * a.density
然后需要找到从矩形质心(所有角落的平均位置)指向接触点(矩形碰撞处)的向量,我们称之为“r”。
接着需要找到碰撞法线。该法线指向施加在a上的冲量的方向,且长度为1单位。在本例中,法线可能指向上方。我们将法线向量称为“n”。
现在需要矩形a上接触点的速度。如果a没有旋转,则公式为:
vp = a.vel
如果a正在旋转,则公式为:
vp = a.vel + cross(a.r_vel, r)
a.r_vel表示以弧度表示的a的旋转速度,正方向为逆时针方向。
cross()表示叉积,函数为:
cross (v,i) = [-i * v.y , i * v.x]
展开的公式为:
vp = a.v + [-r * a.r_vel.y , r * a.r_vel.x]
现在需要计算物体是否朝向对方移动。将vp投影到n上。
vp_p = dot(vp, n)
dot (v1, v2) = v1.x * v2.x + v1.y * v2.y
vp_p是一个标量(一个值,而非矢量)。
如果vp_p为负,则物体朝向对方移动;如果vp_p > 0,则它们正在分开。
现在需要计算阻止a进入b的冲量,该冲量为:
j = -vp_p / ( 1/a.mass + cross(r,n)^2 / a.i )
两个向量的叉积为:
cross(v1,v2) = v1.x * v2.y - v1.y * v2.x
它返回一个标量。
将冲量乘以法线得到冲量向量:
jn = j * n
现在需要将冲量应用于a:
a.new_vel = a.old_vel + jn / a.mass;
a.new_r_vel = a.old_r_vel + cross(r,jn) / a.i;
如果希望碰撞是完全弹性的,则必须将冲量乘以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不是静态的,那么算法会略有不同:
a.r = 指向从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;
公式的工作原理/来源: