Hi,
I am attempting to replace the contact manifold generation logic for box/box overlap with my own. So I am basically adding a user algorithm for the box-box collision case. I have a few questions regarding the contact pairs which are generated for a single manifold between 2 boxes.
1. The manifold can have 1,2,3 or 4 pairs. Are there any specific conditions when 2 pairs are generated or 3, 4 etc? For example I have noticed that for bodies resting on each other 2 pairs seem to be enough.
2. If I choose a bunch of contact points and add them using btDiscreteCollisionDetectorInterface:addContactPoint(), then will bullet take care of ordering the contact pairs correctly such that they are in a clockwise or anticlockwise order (for 3 or 4 pairs), or are there certain guidelines to be followed while adding contact pairs ?
Adding contact pairs through a user collision algorithm
-
- Posts: 66
- Joined: Sun Jan 30, 2011 8:46 pm
-
- Posts: 66
- Joined: Sun Jan 30, 2011 8:46 pm
Re: Adding contact pairs through a user collision algorithm
ok so I have modified the box-box collision algorithm to insert contact pairs. The contact pairs are generated by a custom algorithm and are exactly the same as generated by the box-box detector used by Bullet.
btBoxBoxCollisionAlgorithm.cpp was modified in just one function : processCollision(). The rest of the code is exactly the same (except for commenting out some of the Bullet contact pair generation logic). I call the following function in the added code :
I have calculated the normal and penetration depth correctly. Yet Bullet does not apply a force to hold a box in place when its lying on the top of a bigger box (gravity has been added to the dynamic world). The minute I switch back to Bullet's own logic, the boxes are stable. What am I doing wrong while inserting my own manifolds ?
I am going to hardcode the manifold points that Bullet generates, and insert them using the insert them with addContactPoint() while removing the calls to
...and see if that works.
btBoxBoxCollisionAlgorithm.cpp was modified in just one function : processCollision(). The rest of the code is exactly the same (except for commenting out some of the Bullet contact pair generation logic). I call the following function in the added code :
Code: Select all
resultOut->addContactPoint(ptB, normalWorldOnB,
-(current_manifold->rt_contacts[i].depth));
I am going to hardcode the manifold points that Bullet generates, and insert them using the insert them with addContactPoint() while removing the calls to
Code: Select all
btBoxBoxDetector detector(box0, box1);
detector.getClosestPoints(input, *resultOut, dispatchInfo.m_debugDraw);
Last edited by dumbo2007 on Wed Oct 19, 2011 5:34 pm, edited 1 time in total.
-
- Posts: 66
- Joined: Sun Jan 30, 2011 8:46 pm
Re: Adding contact pairs through a user collision algorithm
Hmm still no luck, I am currently testing with a simple case of a box lying on a plane :

The cube is a unit cube lying on a larger cuboid that is quite thin along the Z axis (I have kept Z axis as up and gravity acts towards -ve Z)

The code I use after registering the custom collision algorithm is as follows in processCollision() :
So I currently create manifold points based on the overlap volume, which is marked in pink above. Its dimensions are of course much thinner than those exaggerated above. struct rigid_body is a custom data structure a pointer to which is stored in the rigid body user pointer member. Its gives access to the manifold contact pairs of the rigid body inside the collision pipeline. The contact pairs are generated in the nearphase callback which is invoked by Bullet before processCollision() is called.

Thus if the Box is penetrating the ground plane (GP), which is also a thin box, then the manifold points for the particular case in the picture can be
resultOut->addContactPoint( (0,0,1), (0,0,-0.001), 0.001);
resultOut->addContactPoint( (0,0,1), (0,0,-0.001), 0.001);
where the points belonging to B are the bottom points in the overlap region marked in pink.
This allows it to calculate the points for body A (the box) using
pointA = pointB + normalBtoA * depth
Well, the box continues to pass through the ground plane after I do this even though I can see that the contact points I feed are being processed (using a contact processed callback).


Here is some output from the callback, when I am injecting my own points (i.e. not bullet's default boxbox contact pair generator ) :
Iteration 1
Iteration 2
and so on, the box A continues to pass through the ground plane B in successive iterations. So what else do I need to set apart from calling addContactPoints() ? If I see the points generated by Bullet then I see that A penetrates B initially but is gradually pushed out after iteration 12, and is then stable after about 25, not the same with my case however 

The cube is a unit cube lying on a larger cuboid that is quite thin along the Z axis (I have kept Z axis as up and gravity acts towards -ve Z)

The code I use after registering the custom collision algorithm is as follows in processCollision() :
Code: Select all
void
btRTCollisionAlgorithm::processCollision(btCollisionObject* body0,
btCollisionObject* body1,
const btDispatcherInfo& dispatchInfo,
btManifoldResult* resultOut)
{
if (!m_manifoldPtr)
return;
btCollisionObject* col0 = body0;
btCollisionObject* col1 = body1;
#ifndef DEBUG_MF
btBoxShape* box0 = (btBoxShape*)col0->getCollisionShape();
btBoxShape* box1 = (btBoxShape*)col1->getCollisionShape();
#endif //DEBUG_MF
//quellage
bu_log("%d", dispatchInfo.m_stepCount);
/// report a contact. internally this will be kept persistent, and contact reduction is done
resultOut->setPersistentManifold(m_manifoldPtr);
#ifndef USE_PERSISTENT_CONTACTS
m_manifoldPtr->clearManifold();
#endif //USE_PERSISTENT_CONTACTS
btDiscreteCollisionDetectorInterface::ClosestPointInput input;
input.m_maximumDistanceSquared = BT_LARGE_FLOAT;
input.m_transformA = body0->getWorldTransform();
input.m_transformB = body1->getWorldTransform();
#ifndef DEBUG_MF
//This part will get replaced with a call to rt
btBoxBoxDetector detector(box0, box1);
detector.getClosestPoints(input, *resultOut, dispatchInfo.m_debugDraw);
#endif //DEBUG_MF
//------------------- DEBUG ---------------------------
int i;
//Get the user pointers to struct rigid_body, for printing the body name
struct rigid_body *rbA = (struct rigid_body *)col0->getUserPointer();
struct rigid_body *rbB = (struct rigid_body *)col1->getUserPointer();
if (rbA != NULL && rbB != NULL) {
//Find the manifold in rbB's list which connects rbB and rbA
if( BU_STR_EQUAL(rt_mf->rbA->rb_namep, rbA->rb_namep) &&
BU_STR_EQUAL(rt_mf->rbB->rb_namep, rbB->rb_namep) ){
// Now add the RT contact pairs
for (i=0; i<rt_mf->num_contacts; i++){
btVector3 ptA, ptB, normalWorldOnB;
VMOVE(ptA, rt_mf->contacts[i].ptA);
VMOVE(ptB, rt_mf->contacts[i].ptB);
VMOVE(normalWorldOnB, rt_mf->contacts[i].normalWorldOnB);
//Positive depth for penetration
resultOut->addContactPoint(normalWorldOnB, ptB, rt_mf->contacts[i].depth);
bu_log("processCollision: Added RT contact %d, %s(%f, %f, %f) , \
%s(%f, %f, %f), n(%f, %f, %f), %f\n",
i+1,
rt_mf->rbA->rb_namep, V3ARGS(ptA),
rt_mf->rbB->rb_namep, V3ARGS(ptB),
V3ARGS(normalWorldOnB),
rt_mf->contacts[i].depth);
}
}//end- if( bu_strcmp...
} //end- if (rbA != NULL && rbB...
//------------------------------------------------------
#ifdef USE_PERSISTENT_CONTACTS
// refreshContactPoints is only necessary when using persistent contact points.
// otherwise all points are newly added
if (m_ownManifold) {
resultOut->refreshContactPoints();
}
#endif //USE_PERSISTENT_CONTACTS
}

Thus if the Box is penetrating the ground plane (GP), which is also a thin box, then the manifold points for the particular case in the picture can be
- (0,0,0)
(1,0,-0.001)
(1,0,-0.001)
(0,0,-0.001)
resultOut->addContactPoint( (0,0,1), (0,0,-0.001), 0.001);
resultOut->addContactPoint( (0,0,1), (0,0,-0.001), 0.001);
where the points belonging to B are the bottom points in the overlap region marked in pink.
This allows it to calculate the points for body A (the box) using
pointA = pointB + normalBtoA * depth
Well, the box continues to pass through the ground plane after I do this even though I can see that the contact points I feed are being processed (using a contact processed callback).


Here is some output from the callback, when I am injecting my own points (i.e. not bullet's default boxbox contact pair generator ) :
Iteration 1
Code: Select all
Contact processed between sim_box.r(0.000000, 1.000000, 0.000000) & sim_gp.r(0.000000, 1.000000, 0.000000)!
Contact processed between sim_box.r(0.000000, 0.000000, 0.000000) & sim_gp.r(0.000000, 0.000000, 0.000000)!
Contact processed between sim_box.r(1.000000, 0.000000, 0.000000) & sim_gp.r(1.000000, 0.000000, 0.000000)!
Contact processed between sim_box.r(1.000000, 1.000000, 0.000000) & sim_gp.r(1.000000, 1.000000, 0.000000)!
Iteration 2
Code: Select all
Contact processed between sim_box.r(0.000000, 1.000000, 0.000000) & sim_gp.r(0.000000, 1.000000, -0.000001)!
Contact processed between sim_box.r(0.000000, 0.000000, 0.000000) & sim_gp.r(0.000000, 0.000000, -0.000001)!
Contact processed between sim_box.r(1.000000, -0.000000, 0.000000) & sim_gp.r(1.000000, 0.000000, -0.000001)!
Contact processed between sim_box.r(1.000000, 1.000000, 0.000000) & sim_gp.r(1.000000, 1.000000, -0.000001)!

-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
Re: Adding contact pairs through a user collision algorithm
Contacts points require negative depth values for penetration.
Positive distance (depth) means they are separated.
Also, the contact normal needs to point from object B towards object A and the contact point needs to be located on the surface of object B.
Can you try that?
If that still doesn't work, can you compare the distance/normal with a simpler case (sphere/sphere)?
Thanks,
Erwin
Positive distance (depth) means they are separated.
Also, the contact normal needs to point from object B towards object A and the contact point needs to be located on the surface of object B.
Can you try that?
If that still doesn't work, can you compare the distance/normal with a simpler case (sphere/sphere)?
Thanks,
Erwin
-
- Posts: 66
- Joined: Sun Jan 30, 2011 8:46 pm
Re: Adding contact pairs through a user collision algorithm
Hi Erwin,
Thanks for the reply. Well it works for the simple case of a sphere - sphere collision.

I made sure the normal points from the object Bullet considers as object B, to the object Bullet takes as object A. The depth calculation is the same as in btSphereSphereCollisionAlgorithm.cpp
The box-box case then also should work, since the only difference in that case is that I am adding 4 contact points in 1 go(right at the 1st call, without any accumulation of points over multiple iterations) instead of the single contact point of sphere-sphere. I will try the box-box collision again.
Thanks for the reply. Well it works for the simple case of a sphere - sphere collision.

Code: Select all
void
btRTCollisionAlgorithm::processCollision(btCollisionObject* col0,
btCollisionObject* col1,
const btDispatcherInfo& dispatchInfo,
btManifoldResult* resultOut)
{
if (!m_manifoldPtr)
return;
//quellage
bu_log("%d", dispatchInfo.m_stepCount);
/// report a contact. internally this will be kept persistent, and contact reduction is done
resultOut->setPersistentManifold(m_manifoldPtr);
#ifndef USE_PERSISTENT_CONTACTS
m_manifoldPtr->clearManifold();
#endif //USE_PERSISTENT_CONTACTS
//------------------- DEBUG ---------------------------
int i;
//Get the user pointers to struct rigid_body, for printing the body name
struct rigid_body *rbA = (struct rigid_body *)col0->getUserPointer();
struct rigid_body *rbB = (struct rigid_body *)col1->getUserPointer();
if (rbA != NULL && rbB != NULL) {
//Scan all raytrace generated manifolds of rbB looking for a rbA-rbB manifold----------------------
struct sim_manifold *rt_mf = &(rbB->rt_manifold);
//Find the manifold in rbB's list which connects rbB and rbA
if( BU_STR_EQUAL(rt_mf->rbA->rb_namep, rbA->rb_namep) &&
BU_STR_EQUAL(rt_mf->rbB->rb_namep, rbB->rb_namep) ){
// Now add the contact pairs
for (i=0; i<rt_mf->num_contacts; i++){
btVector3 ptA, ptB, normalWorldOnB;
VMOVE(ptA, rt_mf->contacts[i].ptA);
VMOVE(ptB, rt_mf->contacts[i].ptB);
VMOVE(normalWorldOnB, rt_mf->contacts[i].normalWorldOnB);
//Negative depth for penetration
resultOut->addContactPoint(normalWorldOnB, ptB, rt_mf->contacts[i].depth);
bu_log("processCollision: Added contact %d, A(ignore): %s(%f, %f, %f) , \
B: %s(%f, %f, %f), n(%f, %f, %f), depth=%f\n",
i+1,
rt_mf->rbA->rb_namep, V3ARGS(ptA),
rt_mf->rbB->rb_namep, V3ARGS(ptB),
V3ARGS(normalWorldOnB),
rt_mf->contacts[i].depth);
}
}//end- if( bu_strcmp...
} //end- if (rbA != NULL && rbB...
}
The box-box case then also should work, since the only difference in that case is that I am adding 4 contact points in 1 go(right at the 1st call, without any accumulation of points over multiple iterations) instead of the single contact point of sphere-sphere. I will try the box-box collision again.
-
- Posts: 66
- Joined: Sun Jan 30, 2011 8:46 pm
Re: Adding contact pairs through a user collision algorithm
ok now the box-box collision also work. Seems the normals were probably wrong. I tried to use the sphere-sphere collision algorithm with 2 boxes to check if contact pairs decide object collisions, and it worked as well with one of the boxes rolling into and penetrating the other as if it were a sphere.
I have another question. I tested the box-box contact pair generation using the following setup of 2 boxes on top of each other :

The bottom box B is static, A can move. During the simulation I found that A continues to penetrate B at least till iteration 20 before stabilizing at 0.00041:

The default box-box collision algorithm does not show this behavior however. In fact the penetration is 0 and stays at 0 for it. In my case I need to have some penetration before I can generate contact pairs, but the penetration should not increase beyond the first few iterations as Bullet starts applying a force to stop it(I assume)
I have another question. I tested the box-box contact pair generation using the following setup of 2 boxes on top of each other :

The bottom box B is static, A can move. During the simulation I found that A continues to penetrate B at least till iteration 20 before stabilizing at 0.00041:

The default box-box collision algorithm does not show this behavior however. In fact the penetration is 0 and stays at 0 for it. In my case I need to have some penetration before I can generate contact pairs, but the penetration should not increase beyond the first few iterations as Bullet starts applying a force to stop it(I assume)