2D物理引擎碰撞响应对象的旋转

8
我正在编写自己的基本物理引擎,现在遇到了一个无法解决的问题。可能是因为我不知道如何在谷歌上搜索这个问题。
所以这就是我的问题。希望这张图片可以解释清楚: 碰撞响应 我有两个物体。灰色的物体固定不动,绿色的物体从顶部落下。 绿色物体有三个向量:一个力、加速度和速度。它与固定的灰色物体发生碰撞。
真正的问题是,当绿色物体掉落时,我如何得到它的旋转?
3个回答

13

看起来你可能没有理解刚体动力学基础物理原理。我这么说是因为你在谈论这类问题时没有提到常用的术语。你需要为系统中的每个动态体引入方向和角速度(位置和线速度的旋转对应物),并计算各种中间量,例如惯性矩、角加速度和力矩。

也许最好的入门参考资料是Chris Hecker在Game Developer Magazine上发表的系列文章。假设你已经解决了非旋转动力学(第1部分介绍)和碰撞检测(本系列不涉及)问题,你应该从第2部分开始,然后继续第3部分。它们将为你实现旋转碰撞响应所需的物理和数学基础打下坚实基础。


哇,这是一个很棒的资源。不确定为什么我之前没有发现它。 - Elliot Winkler

12

当物体碰撞时,根据以下步骤进行操作:

我们将绿色矩形称为“a”,另一个矩形称为“b”。

1.

首先需要确定矩形的“旋转质量”,也就是惯性质量。

a.i = 4/3 * width * height * (width^2 + height^2) * a.density

2.

然后需要找到从矩形质心(所有角落的平均位置)指向接触点(矩形碰撞处)的向量,我们称之为“r”。

3.

接着需要找到碰撞法线。该法线指向施加在a上的冲量的方向,且长度为1单位。在本例中,法线可能指向上方。我们将法线向量称为“n”。

4.

现在需要矩形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]

5.

现在需要计算物体是否朝向对方移动。将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,则它们正在分开。

6.

现在需要计算阻止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

7.

现在需要将冲量应用于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;

公式的工作原理/来源:

http://www.myphysicslab.com/collision.html#resting_contact


1
我没听懂你解释的一半,但看起来你知道你在说什么。所以我点了个赞 :D - rint

0
万一有人偶然发现这个帖子,维基百科有一个3D方法(链接1:https://en.wikipedia.org/wiki/Collision_response)。 记住,逆惯性以世界坐标系表示,即使用物体的旋转将本地逆惯性转换为世界坐标系。
注意向量运算的顺序!(有两个叉乘,它们需要按正确的顺序) cross(inverse a.i * cross(a.r, jn)), a.r) + cross(inverse b.i * cross(b.r, jn)), b.r) 然后使用得到的向量与法线进行点积,以得到分母的一个标量部分。
(花了我很长时间才发现我简单地按错误的顺序乘以逆惯性,导致结果奇怪 - 更正后,我的结果看起来更真实!)
维基百科的参考资料还包括带有代码的参考(链接2:https://www.cs.cmu.edu/~baraff/sigcourse/notesd2.pdf#page=16)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接