Collision Detection Problems with b2ContactEdge and b2Distance
nocholasrift opened this issue · comments
Hi there! I am currently working with the author of mvsim: https://github.com/MRPT/mvsim, which is a robot simulator which uses Box2D for collision detection. Box2D works great for preventing objects from penetrating each other. However, when we try to set a flag to true to expose this collision to the user, the behavior is inconsistent. Specifically, the problem seems to happen mostly when two edges are face to face (parallel), but occasionally happens for corner edges.
Current there are two techniques used to detect collision:
- b2ContactEdge->contact->isTouching()
- b2Distance() with the fixtures -- it works great sometimes, others it returns a large distance, even if the two bodies are face to face with two edges colliding.
Here is a link to the issue in which we are discussing this problem: MRPT/mvsim#42
Any help would be greatly appreciated! Is there a better way to detect collisions than this method?
Attached below is the dump file as requested as a follow up from my Discord post, where the robot crashed head on into an obstacle, and using both 1 and 2 failed to detect the collision:
box2d_dump.zip
Are calling b2Distance directly? I need the data you are sending to that specific function. The world dump doesn't give me the data you send to that function. You'll have to print the input yourself somehow.
I'm guessing you increased b2_maxPolygonVertices
? But looking at your geometry it doesn't seem necessary. Also you are creating 514 joints between static bodies.
Is there some cleaner way to accomplish this printout of the data other than going through the docs and printing every member of every struct and class used? This is the code being used to try and detect the collisions, would I be trying to print all the fields relevant to dO, dc, and di?
// Instantaneous collision flag:
isInCollision_ = false;
if (b2ContactEdge* cl = b2dBody_->GetContactList(); cl != nullptr)
{
for (auto contact = cl->contact; contact != nullptr;
contact = contact->GetNext())
{
// We may store with which other bodies it's in collision?
const auto shA = cl->contact->GetFixtureA()->GetShape();
const auto shB = cl->contact->GetFixtureB()->GetShape();
if (cl->contact->GetFixtureA()->IsSensor()) continue;
if (cl->contact->GetFixtureB()->IsSensor()) continue;
b2DistanceInput di;
di.proxyA.Set(shA, 0 /*index for chains*/);
di.proxyB.Set(shB, 0 /*index for chains*/);
di.transformA =
cl->contact->GetFixtureA()->GetBody()->GetTransform();
di.transformB =
cl->contact->GetFixtureB()->GetBody()->GetTransform();
di.useRadii = true;
b2SimplexCache dc;
dc.count = 0;
b2DistanceOutput dO;
b2Distance(&dO, &dc, &di);
if (dO.distance < simulable_parent_->collisionThreshold() ||
cl->contact->IsTouching())
isInCollision_ = true;
}
}
Set a breakpoint before the call to b2Distance
, then in the watch window put in di
, expand it and then copy the values. You should also list the proxy vertices.
Here is some example data I captured in Visual Studio.
- distanceInput {proxyA={m_buffer=0x000000eb168fee90 {{...}, {...}} m_vertices=0x000000eb168ff1d0 {x=-4.00000000 y=1.00000000 } ...} ...} b2DistanceInput
- proxyA {m_buffer=0x000000eb168fee90 {{x=-4.00000000 y=1.00000000 }, {x=-5.00000000 y=5.00000000 }} m_vertices=...} b2DistanceProxy
+ m_buffer 0x000000eb168fee90 {{x=-4.00000000 y=1.00000000 }, {x=-5.00000000 y=5.00000000 }} b2Vec2[2]
+ m_vertices 0x000000eb168ff1d0 {x=-4.00000000 y=1.00000000 } const b2Vec2 *
m_count 2 int
m_radius 0.00999999978 float
- proxyB {m_buffer=0x000000eb168feeb0 {{x=-107374176. y=-107374176. }, {x=-107374176. y=-107374176. }} m_vertices=...} b2DistanceProxy
+ m_buffer 0x000000eb168feeb0 {{x=-107374176. y=-107374176. }, {x=-107374176. y=-107374176. }} b2Vec2[2]
+ m_vertices 0x000002a0fdb64c70 {x=0.00000000 y=0.00000000 } const b2Vec2 *
m_count 1 int
m_radius 1.00000000 float
- transformA {p={x=0.00000000 y=0.00000000 } q={s=0.00000000 c=1.00000000 } } b2Transform
+ p {x=0.00000000 y=0.00000000 } b2Vec2
+ q {s=0.00000000 c=1.00000000 } b2Rot
- transformB {p={x=-3.27151895 y=6.73861551 } q={s=0.00000000 c=1.00000000 } } b2Transform
+ p {x=-3.27151895 y=6.73861551 } b2Vec2
+ q {s=0.00000000 c=1.00000000 } b2Rot
useRadii false bool
- distanceInput.proxyA.m_vertices,2 0x000000eb168ff1d0 {{x=-4.00000000 y=1.00000000 }, {x=-5.00000000 y=5.00000000 }} const b2Vec2[2]
+ [0] {x=-4.00000000 y=1.00000000 } const b2Vec2
+ [1] {x=-5.00000000 y=5.00000000 } const b2Vec2
- distanceInput.proxyB.m_vertices,1 0x000002a0fdb64c70 {{x=0.00000000 y=0.00000000 }} const b2Vec2[1]
+ [0] {x=0.00000000 y=0.00000000 } const b2Vec2
@erincatto Apologies for the delay, here is a a dump of what was contained in di right before the function call. Is the nan
value I'm seeing in the proxyA m_buffer to blame? The setup is same as before, there is a head on collision between the robot and the obstacle, but the current way the box2D api is being used isn't detecting any collision (last if statement in code provided above is false).
Locals
angle 0 float
cl @0x555555c7f8e0 b2ContactEdge
contact @0x555555c7f8a0 b2Contact
context @0x7fffffffdf60 mvsim::TSimulContext &
dO @0x7fffffffddd0 b2DistanceOutput
dc @0x7fffffffddf4 b2SimplexCache
di @0x7fffffffde00 b2DistanceInput
proxyA @0x7fffffffde00 b2DistanceProxy
m_buffer @0x7fffffffde00 b2Vec2[2]
[0] @0x7fffffffde00 b2Vec2
x nan float
y 4.591634678053128e-41 float
[1] @0x7fffffffde08 b2Vec2
x 34816179306496.0 float
y 3.061136495317563e-41 float
m_count 4 int32
m_radius 0.00999999978 float
m_vertices @0x555555d56b08 b2Vec2
x 0.0299999937 float
y 0.144999996 float
proxyB @0x7fffffffde20 b2DistanceProxy
m_buffer @0x7fffffffde20 b2Vec2[2]
[0] @0x7fffffffde20 b2Vec2
[1] @0x7fffffffde28 b2Vec2
m_count 14 int32
m_radius 0.00249999994 float
m_vertices @0x555555fb9938 b2Vec2
x 0.0769287646 float
y 0 float
transformA @0x7fffffffde40 b2Transform
p @0x7fffffffde40 b2Vec2
x -3.195467 float
y 5.40175343 float
q @0x7fffffffde48 b2Rot
c -0.851679325 float
s 0.524063289 float
transformB @0x7fffffffde50 b2Transform
p @0x7fffffffde50 b2Vec2
x -3.67499995 float
y 5.4749999 float
q @0x7fffffffde58 b2Rot
c 1 float
s 0 float
useRadii true bool
lck @0x7fffffffdd80 std::unique_lock<std::shared_mutex>
pos @0x555555f45f2c b2Vec2 &
shA @0x555555d56af0 b2Shape
shB @0x555555fb9920 b2Shape
this @0x555555fd76d0 mvsim::Block
vel @0x555555f45f60 b2Vec2 &
w 0 float
Inspector
Expressions
Return Value
Tooltip