1

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

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

情况1

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

案例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 

尽管正确设置 tri info 并验证代码执行正常,但使用 NBbtAdjustInternalEdgeContacts并没有任何明显的帮助。虽然它确实有效并且对模拟的可靠性有一些小的改进(尽管 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

4

1 回答 1

1

The problem happened because there are multiple collisions happening between the two objects - the same goes with sphere<->tri collision. Not only does the collision detector detects the tri surface collision, ending the iteration for the surface triangle (as expected), but also it keeps traversing the BVH (also as kind-of-expected), resulting in another collision with the adjacent triangle's edge. This can be reproduced in many ways, e.g. by throwing an object close to a trimesh edge (but still on the inside part of the mesh!), by throwing an object near an internal tri border (edge) but asymmetrically (symmetric drop would result in edge forces canceling out). The object will fly to the side (sometimes wildly) even if the surface is perfectly flat at that point.

The only versatile solution that came to my mind and doesn't require a thorough rewrite of Bullet 2 code is to filter the colliding object's manifold in e.g. in gContactStartedCallback, finding all surface collisions and removing all edge collisions for all edges adjacent to that surface. Watching for numContacts >= 2 on given trimesh's manifolds is usually the way to go; this shouldn't happen too often, and checking a couple of points on a manifold is not that CPU intensive.

Removing contacts based on their distance also works wonders here, although that's way too crude/context specific of a fix to be used in production code IMO. I'm still looking for a simpler and more efficient solution though.

Also, a partial workaround (as noted in one of the forum discussions) was to change the timestep values; the default one fails for triangle meshes vs any object moving with reasonable speed. For "regular speeds", fixed timestep of max 1/300 is needed, for "high speeds" 1/600 or even less, YMMV. Note that it increases the CPU load a lot and only reduces the problem, in many situations not solving it at all.

The related issue has been posted on Bullet's issue tracker here.

于 2014-11-18T13:49:05.917 回答