【发布时间】:2020-11-15 18:31:40
【问题描述】:
我正在用 Python 开发一个物理引擎(我知道,它主要用于“学习”),并且运行良好。我一直在关注很多关于这个问题的在线文档,这一系列文章特别有帮助:How to Create a Custom Physics Engine。
我的材料正在工作,它们充当一个包含 restitution 和 density 的类。接下来发生的是具有低密度和高复原力(例如分别为 0.3 和 0.8)的物体,它们以如此高的速度相互反弹,以至于它们很快就会射入“虚空”。
我有一个测试场景,有 4 面墙包围着身体(球)。当它们以如此高的速度行驶时,永远不会记录碰撞,因为下一次物理模拟发生在它们已经通过“墙壁”之后。
我真正感兴趣的是为什么它们在相互反弹时会获得如此高的速度,而我认为它们不应该如此。在我的示例录制中,我有一个小球(红色),由玩家(我)控制。它的密度为 0.3,复原率为 0.8,体积为 100(r * r 或 10 * 10),质量为 30 KGs(100 * 0.3)。另一个较大的球(绿色)不是玩家的控制者,但可以通过用红色球击中它来反弹。它具有相同的材料,因此具有相同的密度和复原力。但是,由于半径较大 (30),它的质量较高。绿球的实际质量是 270 (900 * 0.8)。
在录音中,可以看到球以不自然的方式相互反弹。小球不应该比大球受到更大的冲击吗?我试图通过交换计算脉冲时使用的质量值来解决这个问题。所以小球的冲量是用大球的质量来计算的,反之亦然。你会认为这是因为更大的球质量更高,但对我来说,它们彼此反弹得相当快?
这是我在这两个球上的密度和恢复力的正常行为吗?如果需要,我将共享代码,但由于本文已经有点长,如果不需要,我不会浪费空间。我的代码几乎完全遵循文章中的内容,只是“转换”为 Python 代码。
计算冲动的代码
# Relative velocity
rv = b.velocity - a.velocity
# Velocity along the normal direction
vel_along_normal = rv.dot(contact_normal)
# EPSILON (use lowest restitution value)
e = min(a.restitution, b.restitution)
# Calculate j, which will be used to get the impulse
j = -(1 + e) * vel_along_normal
j /= a_inv_mass + b_inv_mass
impulse = contact_normal * j
# Using ratio to have lighter bodies bounce with a higher impulse than heavier bodies
mass_sum = a_mass + b_mass
ratio = (b_mass / mass_sum)
a.rigid_body.velocity -= (impulse * ratio) * dt
ratio = (a_mass / mass_sum)
b.rigid_body.velocity += (impulse * ratio) * dt
【问题讨论】:
-
Restitution
e是一个 0 到 1 之间的值。假设 e 在e = min(a.restitution, b.restitution)之后是一个正值,那么下一行j = -(1 + e) * vel_along_normal是不正确的,因为它使(1 + e) > 1增加了能量碰撞(在现实世界中不应该发生)。由于不清楚您如何定义e我会假设标准定义并说计算j的行应该是j = -e * vel_along_normal -
当像这样更改代码时,球只是撞到对撞机上,什么也不做。正如您所说,恢复值是 0 到 1。球的
e为 0.8,因此它的弹跳应该很高。但事实并非如此。 -
我设法让它工作,我没有乘以 dt。不过,他们仍然表现得很奇怪。对于静止的物体,它似乎可以正常工作,但是一旦两者都移动,它们就会突然开始超快。
-
似乎身体越重,它跑得越快,但只针对静止的物体。我相信这是因为静止物体的质量为 0(无限质量)。所以
j没有正确计算,因为 0 inverse_mass。如果其中一个物体的质量是无限的,我应该使用什么值? -
现在我想起来了,当一堵墙有无限的质量时,它不应该像我们看到的那样发回一个高脉冲吗?所以,我猜运动学的原因是为了解决这个问题。所以你仍然可以有质量,但要防止身体受到力的影响。
标签: python game-physics physics physics-engine