找到一种在边缘碰撞中修复错误碰撞法线的方法

Posted

技术标签:

【中文标题】找到一种在边缘碰撞中修复错误碰撞法线的方法【英文标题】:find a way of fixing wrong collision normals in edge collisions 【发布时间】:2015-01-04 12:07:08 【问题描述】:

主要问题是 Bullet 2(具体来说是 2.82 - 也许 Bullet 3 还没有检查过)糟糕地处理边缘碰撞,产生倾斜的反应法线。

测试用例 1:一个小的 btBoxShape,定位 (0,9,0),垂直对齐,落在另一个盒子的(也由 btBoxShape 制成)面上,并列。法线计算正确,碰撞仅发生在 Y(垂直)轴上。框在 OY 轴上轻微反弹并保持围绕它的中心。

测试用例 2:一个小盒子,位于 (0,9,0) 垂直对齐,(同上)落在另一个盒子的面上,(这次是由 btBvhTriangleMeshShape 由 2 个共面三角形组成),也对齐。法线计算不正确,碰撞发生在所有轴上。盒子反弹到一边,有时(取决于特定的碰撞坐标)非常明显。

即使对法线进行硬编码并基于它重新计算碰撞点(见下文)也无济于事。

//newNormal was set to hard-coded value of (0,-1,0) before
cp.m_normalWorldOnB = colObj0Wrap -> getWorldTransform().getBasis() * newNormal;
cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1;
cp.m_localPointB = colObj0Wrap -> getWorldTransform().invXform( cp.m_positionWorldOnB 

NB 使用 btAdjustInternalEdgeContacts 并没有任何明显的帮助,尽管正确设置了 tri info 并验证了代码 is 执行是否正常。虽然它确实工作并且对模拟的可靠性有一些小的改进(尽管 CPU 成本相当高),但它仍然不能解决这个特定问题。

问题是:如何修复案例 2 的行为以匹配案例 1。任何如何避免这种情况的建议(欢迎使用代码拼凑),或者为什么这不能按应有的方式工作。

进一步参考:

https://github.com/bulletphysics/bullet3/issues/92

http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=8113

https://bullet.googlecode.com/files/GDC10_Coumans_Erwin_Contact.pdf

https://code.google.com/p/bullet/issues/detail?id=27

http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=4603

【问题讨论】:

【参考方案1】:

问题的发生是因为两个对象之间发生了 多次 碰撞 - 球体tri 碰撞也是如此。碰撞检测器不仅检测到三表面碰撞,结束表面三角形的迭代(如预期的那样),而且它继续遍历 BVH(也如预期的那样),导致与相邻三角形边缘的另一次碰撞.这可以通过多种方式复制,例如通过将一个物体扔到靠近修剪边缘(但仍然在网格的内部!),通过在内部三边(边缘)附近扔一个物体,但不对称(对称下降会导致边缘力抵消)。物体会飞到一边(有时很疯狂),即使此时表面完全平坦。

我想到的唯一一个不需要彻底重写 Bullet 2 代码的通用解决方案是过滤碰撞对象的流形,例如在gContactStartedCallback 中,查找所有表面碰撞并移除与该表面相邻的所有边缘的所有边缘碰撞。在给定的 trimesh 的流形上观察numContacts >= 2 通常是要走的路;这不应该经常发生太多,并且检查流形上的几个点并不是 CPU 密集型的。

根据他们的距离删除联系人在这里也能产生奇迹,尽管这对于在生产代码 IMO 中使用的修复来说过于粗糙/特定于上下文。不过,我仍在寻找更简单、更有效的解决方案。

此外,部分解决方法(如论坛讨论中所述)是更改时间步长值;对于三角形网格与任何以合理速度移动的对象,默认设置失败。对于“常规速度”,需要最大 1/300 的固定时间步长,对于“​​高速”,需要 1/600 甚至更少的 YMMV。请注意,它会大大增加 CPU 负载,只会减少问题,在许多情况下根本无法解决问题。

相关问题已发布在 Bullet 的问题跟踪器 here。

【讨论】:

谢谢。 +1 除了错误跟踪器之外,如果您还附上一些(官方?)教程的链接,那就更好了。 XD 具体来说,我正在尝试解决 ***.com/questions/25605659/… :一个 btRigidBody 在 2 个非常靠近的 btRigidBody 上滑动。不幸的是,它目前的最佳答案(使用 ray)是一个 hack。对于随机碎片来说太昂贵和乏味了。我想修复的方法将涉及btInternalEdgeUtilityContactAddedCallback。但是,它可能仅适用于解决单个 btBvhTriangleMeshShape 内的正常冲突。 @cppBeginner 在这种情况下我能给你的唯一建议是手动过滤碰撞,实际上是通过使用回调(就像我提到的那样,btInternalEdgeUtility 在我的情况下效果不佳)。在我的应用程序中,在ContactAddedCallback 中,我添加了(除其他外)对过滤方法的调用,gist.github.com/FyiurAmron/3fa2d6b55fd96e50a6cce93f5859f680 - 如果无法使用自定义过滤代码重新编译 Bullet,则 IMVHO 是这里最好的解决方案.只需检查两个联系人是否都是您要检测的联系人,如果是,请删除它们(或其中之一)。 嗯,听起来不错。如果您决定将此 sn-p 作为该胶囊问题的解决方案发布,我也会在那里投票。谢谢。

以上是关于找到一种在边缘碰撞中修复错误碰撞法线的方法的主要内容,如果未能解决你的问题,请参考以下文章

边缘检测 --> CGPath --> SpriteKite 碰撞

CocosCreator 物理引擎中的碰撞平面的法线

Swift + Physics:碰撞时错误的角度计算

没有版本碰撞时释放提醒或提交阻止程序

unity网格碰撞器接缝问题

p2之碰撞