提问人:Georgi B. Nikolov 提问时间:11/13/2023 更新时间:11/13/2023 访问量:23
盒子与平面相撞 - 奇怪的旋转
Colliding a box with a plane - strange rotation
问:
我正在关注《游戏物理引擎开发》一书。我理解拆分碰撞:首先生成一个接触点,然后根据其方向、位置、穿透等解决它。我已经有并且碰撞工作正常。sphere - plane
sphere - sphere
但是,我遇到了重大问题。以下是它当前外观的视频: https://imgur.com/a/YqEjCoKbox - plane
请注意,多维数据集有一些非常可疑的行为。它永远不会停留在一侧,并且永远停留在单个顶点或单个侧面。
我想了解地面和箱子之间第一次发生撞击的时间。请注意,尽管底面的顶点位于同一平面上,以相同的速度行进并同时均匀地撞击地面,但最终会对每个顶点施加不同的冲量,并且错误地产生旋转。
我接下来的书找到了穿透力最大的接触点,对其应用旋转/线性变化,然后根据穿透力最大的接触的角度/线性分量调整所有其他接触点的穿透力:
var velocityChange = [float3.zero, float3.zero]
var rotationChange = [float3.zero, float3.zero]
velocityIterationsUsed = 0
while (velocityIterationsUsed < velocityIterations) {
var max = velocityEpsilon
var index = contacts.count
// find contact with greatest "penetration"
for i in 0 ..< contacts.count {
if (contacts[i].desiredDeltaVelocity > max) {
max = contacts[i].desiredDeltaVelocity
index = i
}
}
if (index == contacts.count) {
break
}
// Match the awake state at the contact
contacts[index].matchAwakeState()
// Apply velocity change to the greatest penetration contact
contacts[index].applyVelocityChange(
velocityChange: &velocityChange,
rotationChange: &rotationChange
)
// Loop all generated contacts
for i in 0 ..< contacts.count {
// Check each body in the contact
for b in 0 ..< 2 {
if (contacts[i].bodies[b] != nil) {
// Check for a match with each body in the newly resolved contact
for d in 0 ..< 2 {
if (contacts[i].bodies[b] == contacts[index].bodies[d]) {
let deltaVel = velocityChange[d] + cross(rotationChange[d], contacts[i].relativeContactPosition[b])
print("""
=======================
contact idx \(i):
velocityChange: \(velocityChange[d])
rotationChange: \(rotationChange[d])
relativeContactPosition: (\(contacts[i].relativeContactPosition[b].x) \(contacts[i].relativeContactPosition[b].y) \(contacts[i].relativeContactPosition[b].z))
deltaVel: (\(deltaVel.x) \(deltaVel.y) \(deltaVel.z))
""")
// deltaVel does not make sense on first impact
}
}
}
}
}
}
velocityIterationsUsed += 1
}
请注意基于线性和角度分量重建每个接触速度偏移的变量。在第一次箱子撞击时,当底面的 4 个顶点均匀地、同时以相同的速度撞击地面时,报告了非常奇怪的值:deltaVel
deltaVel
=======================
contact idx 0:
velocityChange: SIMD3<Float>(0.0, 3.1689641, 0.0)
rotationChange: SIMD3<Float>(0.26407933, 0.0, 0.2640793)
relativeContactPosition: (0.5 -0.5010185 -0.50000006)
deltaVel: (0.13230862 3.4330435 -0.13230863)
=======================
contact idx 1:
velocityChange: SIMD3<Float>(0.0, 3.1689641, 0.0)
rotationChange: SIMD3<Float>(0.26407933, 0.0, 0.2640793)
relativeContactPosition: (-0.5 -0.5010185 -0.50000006)
deltaVel: (0.13230862 3.1689641 -0.13230863)
=======================
contact idx 2:
velocityChange: SIMD3<Float>(0.0, 3.1689641, 0.0)
rotationChange: SIMD3<Float>(0.26407933, 0.0, 0.2640793)
relativeContactPosition: (0.5 -0.5010185 0.4999999)
deltaVel: (0.13230862 3.1689641 -0.13230863)
=======================
contact idx 3:
velocityChange: SIMD3<Float>(0.0, 3.1689641, 0.0)
rotationChange: SIMD3<Float>(0.26407933, 0.0, 0.2640793)
relativeContactPosition: (-0.5 -0.5010185 0.4999999)
deltaVel: (0.13230862 2.9048848 -0.13230863)
请注意这条线
let deltaVel = velocityChange[d] + cross(rotationChange[d], contacts[i].relativeContactPosition[b])
它如何为每个顶点产生几乎相同的结果,除了 Y 分量随着每个下一个顶点逐渐减少?但为什么它会减少呢?我在 matlab 中为每个顶点做了这个方程式,它确实是正确的。我的理解是,它应该在所有顶点上相等(因为它们位于同一平面上)?这样,它们都将以相同的 Y 速度反弹,并且不会发生旋转。deltaVel
如您所见,迭代之间唯一不同的值是 .由于盒子的宽度、高度和深度为 1,因此每个轴的这些值约为 +/- 0.5。contact[i].relativeContactPosition
// vertex #1
let linearChange0 = float3(0, 3.1854, 0.0)
let angularChange0 = float3(0.265, 0, 0.265)
let relativeContactPos0 = float3(-0.5, -0.5265012, -0.50000006)
linearChange0 + cross(angularChange0, relativeContactPos0) = (0.139522806, 3.18540001, -0.139522806)
// vertex #2
let linearChange1 = float3(0, 3.1854, 0.0)
let angularChange1 = float3(0.265, 0, 0.265)
let relativeContactPos1 = float3(-0.5, -0.5265012, 0.4999999)
linearChange1 + cross(angularChange1, relativeContactPos1) = (0.139522806, 2.92040014, -0.139522806)
鉴于两个等式之间的唯一区别是值的 Z 分量,为什么生成的 Y 值不同?如何使它们统一?relativeContactPos
TLDR:上面所附的 IMGUR 视频中的每个顶点都具有不同的 Y 速度偏移,即使它们都位于同一平面上,以相同的速度行进。该怎么办?
答:
鉴于两个方程之间的唯一区别是 Z 分量,为什么得到的 Y 价值不同?如何使它们统一?
relativeContactPos
因为你正在采取交叉产品。只有离轴项对生成的轴项有贡献:
你取的是叉积是正确的——毕竟扭矩是叉积——但显然取错了叉积。
为速度变化计算的值 () 是正确的,位置矢量 () 也是如此。velocityChange
relativeContactPos
我们需要的是每个顶点上由于扭矩引起的冲量,我们知道它应该采用以下形式
由于扭矩由下式给出
由于冲量等于力乘以时间,我们可以为扭矩引起的冲量构造这个方程:
但是由于加速度等于速度随时间的变化,因此这变成了
因此,叉积应为
cross(contacts[i].relativeContactPosition[b], velocityChange[d])
这将导致如下所示的完全偏移向量(自上而下视图)
但请注意,这不处理脉冲方面,只处理扭矩方面。扭矩的大小将按质量和时间增量进行缩放。在这种面对面碰撞的特定情况下,这并不重要,因为产生的扭矩会抵消,但在其他情况下,它们的冲量计算会错误地缩放。
由于您尚未包含完成脉冲计算所需的必要信息,因此无法确定您需要做什么,但在广义行程中,扭矩对速度变化的完整贡献将计算为:
cross(contacts[i].relativeContactPosition[b], velocityChange[d]) * deltaT * mass
上一个:如何将弹道弹丸瞄准移动目标?
下一个:UE5中精确的武器握把动画
评论