C# 物理对象';漂移';连续接触时
我一直在尝试做一个简单的3D物理引擎作为练习。我的问题是,当物体与另一个物体接触时,如果它们的位置没有完全对齐,它们就会“漂移” 在我的测试案例中,机顶盒启用了物理功能,并且受到重力的影响。底部框是静态的(其速度固定为0)。如果顶框完全位于底框中心上方(因此它们共享相同的X和Z坐标),则顶框将落在底部并保持完全静止。然而,如果顶框在X轴或Z轴上因事件发生一点偏移,则它在着陆后开始在该方向获得动量,直到最终下降,如图所示 我知道这是什么原因:当完全居中着陆时,EPA提供的触点(我是基于此实现的)位于机顶盒中心的正下方。这将导致雅可比矩阵中指示应用于机顶盒(r1 x法线)的约束扭矩的部分为0。但是,当偏移时,接触点不再直接位于机顶盒的中心下方,导致机顶盒轻微旋转。这反过来会导致下一个时间步上的接触法线稍微旋转。顶盒沿此接触法线向外推,导致其四处滑动。我已经证实了这一点,因为禁用旋转或硬编码来联系normal to 0,-1,0解决了这个问题 我认为实现联系人缓存可以解决这一问题,但正如您在上面的视频中所看到的,每个紫色点代表一个活动联系人。我在多个时间步长上缓存联系人,每当联系人向对象施加力时,它都会更新与该对象(包括其自身)相关的所有联系人的穿透深度:C# 物理对象';漂移';连续接触时,c#,game-physics,C#,Game Physics,我一直在尝试做一个简单的3D物理引擎作为练习。我的问题是,当物体与另一个物体接触时,如果它们的位置没有完全对齐,它们就会“漂移” 在我的测试案例中,机顶盒启用了物理功能,并且受到重力的影响。底部框是静态的(其速度固定为0)。如果顶框完全位于底框中心上方(因此它们共享相同的X和Z坐标),则顶框将落在底部并保持完全静止。然而,如果顶框在X轴或Z轴上因事件发生一点偏移,则它在着陆后开始在该方向获得动量,直到最终下降,如图所示 我知道这是什么原因:当完全居中着陆时,EPA提供的触点(我是基于此实现的)位
您可以找到我的代码(很抱歉,这是choas)。这个问题几乎可以肯定是由于非常小的数字会随着时间的推移产生不同。滑动很小。我克隆了你的repo,但是我没有让它运行的库,所以我能给你的唯一建议就是阅读代码 然而,当我看代码时,这类东西让我非常紧张:
int index = -1;
float maxDot = -9999;
float td = -9999;
float ti = -1;
我知道你想做什么,但这类事情导致了我在过去很难找到很多bug
至于你的Jacoabian问题,如果我没记错我的物理,当雅可比数为0时,这是一个奇点,你的控制力根本不能移动它
看起来你肯定认为,曲面之间的夹角很小。我的最佳想法是,如果两个表面几乎平行(因此,三角形角度低于某个阈值),那么可以禁用该物理过程的某些部分。这可能涉及将对象“捕捉”到稳定状态,您可以描述它们精确排列的位置
因此:
公共静态浮动阈值=0.001f;
公共覆盖无效更新约束(刚体、时间增量、vec3增量、vec3增量)
{
//我知道这种计算德尔塔罗所代表的实际位置增量的方法非常糟糕,但我无法得到任何其他方法(我是一个线性代数新手)。
var rot=(四元轴角((deltaTime*deltaRot).长度,deltaRot.NormalizedSafe)*触点)-触点;
如果(rot<最小阈值)
{
//在这里做一些事情,可能只是返回而不更新。
}
变量deltaPos=(deltaVel*deltaTime)+rot;
//从车身1到车身2的接触法线点
_pendepth+=(Body==Body1?1:-1)*vec3.Dot(deltaPos,_normal);
}
虽然您的代码肯定存在一些问题,但整个系统相当聪明,您应该为您所编写的内容感到自豪。这个问题几乎可以肯定是由于非常小的数字随着时间的推移而产生的差异。滑动非常小。我克隆了您的repo,但我没有库来运行它,因此我能给你的冰只是通过阅读代码 然而,当我看代码时,这类东西让我非常紧张:
int index = -1;
float maxDot = -9999;
float td = -9999;
float ti = -1;
我知道你想做什么,但这类事情导致了我在过去很难找到很多bug
至于你的Jacoabian问题,如果我没记错我的物理,当雅可比数为0时,这是一个奇点,你的控制力根本不能移动它
显然,你似乎认为确实是由曲面之间非常小的角度产生的。我的最佳想法是,如果两个曲面几乎平行(因此delta角度低于某个阈值),那么你可以禁用该物理过程的某些部分。这可能涉及“捕捉”将对象转换为稳定状态,您可以描述它们精确排列的位置
因此:
公共静态浮动阈值=0.001f;
公共覆盖无效更新约束(刚体、时间增量、vec3增量、vec3增量)
{
//我知道这种计算德尔塔罗所代表的实际位置增量的方法非常糟糕,但我无法得到任何其他方法(我是一个线性代数新手)。
var rot=(四元轴角((deltaTime*deltaRot).长度,deltaRot.NormalizedSafe)*触点)-触点;
如果(rot<最小阈值)
{
//在这里做一些事情,可能只是返回而不更新。
}
变量deltaPos=(deltaVel*deltaTime)+rot;
//从车身1到车身2的接触法线点
_pendepth+=(Body==Body1?1:-1)*vec3.Dot(deltaPos,_normal);
}
虽然您的代码肯定存在一些问题,但整个系统相当聪明,您应该为自己所编写的内容感到自豪。我已经实现了类似于您建议的功能。Rigidbo
public static float MinAngleThreshold = 0.001f;
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;
if(rot < MinAngleThreshold)
{
//do something here, potentially just return without updating.
}
var deltaPos = (deltaVel * deltaTime) + rot;
//The contact normal points from Body1 to Body2
_pendepth += (Body == Body1 ? 1 : -1) * vec3.Dot(deltaPos, _normal);
}