【发布时间】:2020-09-21 10:37:00
【问题描述】:
我一直在尝试制作一个简单的 3D 物理引擎作为练习。我的问题是,如果对象的位置没有完全对齐,那么当它们与另一个对象接触时,它们会“漂移”。
在我的测试用例中,顶盒启用了物理功能并受重力影响。底部的盒子是静态的(它的速度固定为 0)。如果顶盒完全位于底盒中心上方(因此它们共享相同的 X 和 Z 坐标),则顶盒会落在底部并完全静止。但是,如果顶盒在 X 或 Z 轴上稍微偏移一点,它会在着陆后开始在该方向上获得动力,直到最终下降,如 here 所示。
我知道是什么原因造成的:当着陆完全居中时,EPA 提供的接触点(我基于this 实施)位于顶盒中心的正下方。这会导致雅可比部分指示要应用于顶盒的约束扭矩 (r1 x normal) 为 0。但是,当偏移时,接触点不在顶盒的正下方盒子的中心不再,导致它稍微旋转。这反过来又会导致下一个时间步的接触法线略微旋转。顶盒沿此接触法线被推出,使其四处滑动。我已经确认了这一点,因为禁用旋转或硬编码以正常接触 0,-1,0 可以解决此问题。
我认为实施联系人缓存可以解决此问题,但正如您在上面的视频中看到的那样,它并没有,其中每个紫色点代表一个活动联系人。我在多个时间步长上缓存联系人,并且每当联系人向对象施加力时,它都会更新与该对象相关的所有联系人(包括其自身)的穿透深度:
private void ApplyForces(RigidBody Body, Time deltaTime, vec3 deltaVel, vec3 deltaRot)
{
Body.ForcesConstraints += deltaVel;
Body.TorqueConstraints += deltaRot;
foreach (Constraint c in M.InvolvedConstraints)
c.UpdateConstraint(Body, deltaTime, deltaVel, deltaRot);
}
public override void UpdateConstraint(RigidBody Body, Time deltaTime, vec3 deltaVel, vec3 deltaRot)
{
//I understand that this way of computing the actual positional delta the deltaRot represents is incredibly bad, but I coulnd't get anything else to work (I'm a linear algebra newbie).
var rot = (quat.FromAxisAngle((deltaTime * deltaRot).Length, deltaRot.NormalizedSafe) * contact) - contact;
var deltaPos = (deltaVel * deltaTime) + rot;
//The contact normal points from Body1 to Body2
_pendepth += (Body == Body1 ? 1 : -1) * vec3.Dot(deltaPos, _normal);
}
你可以找到我的代码here(这是choas,对不起)。
【问题讨论】:
标签: c# game-physics