No hit/collision on convexSweepTest using btBulletWorldImporter

Post Reply
went4lunch
Posts: 4
Joined: Wed Sep 08, 2021 9:45 pm

No hit/collision on convexSweepTest using btBulletWorldImporter

Post by went4lunch »

Still new to Bullet Physics here. I was able to successfully do a discrete collision detection using a static triangle mesh against a collision object with shapes loaded from a .bcs file using btBulletWorldImporter. But that is not good enough for our application so now I'm giving CCD a try using sweep test. I was able to use btCollisionWorld::convexSweepTest on a simple sphere against my triangle mesh and got collision detected at the correct coordinate. But when loading collision shape from .bcs file, no collision got detected even though the object travels on the same vector as the simple sphere through my trianglemesh. I checked it also visually using debugDrawWorld.

Code: Select all

	btCollisionShape* collisionCheck::loadBCS(const char* filename, bool verbose) {
	btBulletWorldImporter loader(0);//don't store info into the world
	loader.setVerboseMode(verbose);
	if (!loader.loadFile(filename)) return NULL;
	btCollisionShape* shape = NULL;
	if (loader.getNumCollisionShapes()>0) shape = loader.getCollisionShapeByIndex(0);
	return shape;
}

Code: Select all

		
	MyContactResultCallback crCallback;
	btCollisionShape* shapeA= loadBCS("Models/Excalibur2_ABAxis.bcs");
	btConvexShape* myCS= static_cast<btConvexShape*>(shapeA);
	prevPtA.setOrigin(btVector3(-100, -200, -500));
	btPtA.setOrigin(btVector3(-500, -200, -500));
	if (prevPtA.getOrigin() != btPtA.getOrigin())
		dynamicsWorld->convexSweepTest(myCS, prevPtA, btPtA, crCallback);
	if (crCallback.hasHit()) {
		cout << "Got a hit!";
	}

I compared the difference between the simple sphere vs the loaded shape and found that when loading the shape, the collision shape type is int 31 vs. int 8 for simple sphere.

and so this line of code in btGjkPairDetector.cpp returns a very low negative number (don't make sense)

Code: Select all

	btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);

Is it bad to cast btCollisionShape to btConvexShape? What's the correct way to use convexSweepTest with .bcs file?
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: No hit/collision on convexSweepTest using btBulletWorldImporter

Post by drleviathan »

convexSweepTest() expects a btConvexShape pointer as first argument. You can only sweep convex shapes.

When I count the BroadphaseNativeTypes enums in btBroadphaseProxy.h I see that 31 corresponds to COMPOUND_SHAPE_PROXYTYPE. But btCompoundShape derives from btCollisionShape not btConvexShape. It is not convex and cannot be used by convexSweepTest().

Continuous Collision Detection (CCD) in Bullet is not "accurate" in general because it sweeps a sphere proxy instead of the actual shape. It is really just an enhancement to the BroadPhase: it tries to catch tunnel events (using convexSweepTest() on the proxy shape) for fast objects that would otherwise not be noticed by the BroadPhase algorithm. The CCD sweeps submit a potentially colliding pair to the NarrowPhase with the fast-moving object transformed to where the proxy shape hit the other rather than where it would have been after a full substep forward. It is the job of the NarrowPhase to compute the actual collision details, if any. But you aren't using CCD per se since you are running your own convexSweepTests; I just point out how CCD works in Bullet for future readers, since you mentioned it.

Now as to your real problem you say:
I was able to successfully do a discrete collision detection...but that is not good enough for our application...
Could you elaborate on what that means? How does the collision detection fail your needs? What do you actually need?
went4lunch
Posts: 4
Joined: Wed Sep 08, 2021 9:45 pm

Re: No hit/collision on convexSweepTest using btBulletWorldImporter

Post by went4lunch »

I have a list of coordinates that represent the path of the object movement and need to check whether it will collide with the static mesh. When doing discrete collision, I put the objects into btDiscreteDynamicsWorld and then call stepSimulation each time after moving the object to a new coordinate. This works well to get the collision detected on the new position. But if the old position is far from the new position some collisions didn't get detected (tunneling). I tried to decrease the distance between old and new coordinates (increase collision checks) but noticed a significant decrease in performance. Decreasing the timestep helps a little but still miss some collision. That's why I decided to try using convexSweepTests.
Could you elaborate what you mean with
you aren't using CCD per se since you are running your own convexSweepTests;
?

Maybe my understanding is not clear. I converted a concave mesh object by using the HACD example to generate the .bcs file. I thought the collisionshape loaded from the .bcs file is considered as convex shapes that can be used for convexSweepTest?
If that's not the case then is the better approach is to first use convexSweepTest using a convex shape representation of the object (not using HACD decomposition) and if there is a hit, do a discrete check using the collisionShape from .bcs file?
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: No hit/collision on convexSweepTest using btBulletWorldImporter

Post by drleviathan »

Perhaps you really are using CCD (which uses convexSweepTest() under the hood), I don't know. But your example snippet code showed you doing a manual convexSweepTest() so I thought maybe you were doing manual sweeps only rather than relying on the CCD sweeps.

For the benefit of future readers I will summarize Bullet CCD

In Bullet CCD is enabled in the World by default, however it is disabled by default for each object. Specifically objects whose CcdMotionThreshold is zero do not get CCD checks. You must enable CCD per object like so:

Code: Select all

body->setCcdMotionThreshold(non_zero_min_speed_at_which_to_apply_sweep_test);
No CCD checks are done until the object's linear speed exceeds the threshold. This to avoid unnecessary CPU cost when normal NarrowPhase checks at step endpoints should suffice.

When the sweep happens the CCD algorithm does not sweep the actual shape of the object. Instead it sweeps a proxy sphere centered along the object's path. When the sweep hits something Bullet will advance the object to the fraction of the sweep hit and then (I think) perform narrow-phase collision checks using the object's real shape.

The default initialized radius of the proxy sphere is zero. That is a bad value to use for a large object since Bullet will advance the object to where the point-like proxy sphere hit, which will already be in a state of penetration for the larger object. Better to catch the object when its outer edge is near collision. You would do this by using a non-zero radius for a better proxy approximation of the real shape:

Code: Select all

body->setCcdSweptSphereRadius(radius);
This works well for compact objects with vaguely spherical hulls, but not necessarily for long skinny convex shapes, or sparse/sharp concave shapes.

You might be tempted to use a very generous bounding sphere for the proxy shape, however in my experience too-large proxies cause visible artifacts where the fast moving object may "stop" early before actually hitting its obstacle: the proxy hits first and somehow contributes contact manifold points which stop the real object too soon.

If your object's shape is not well approximated by a single sphere then... you might be out of luck when it comes to using Bullet's CCD to prevent most of the tunneling events. To work around it maybe you could write a custom expensive CCD algorithm (e.g. one that sweeps multiple spheres), or maybe you could redesign your object to be more spherical.
went4lunch
Posts: 4
Joined: Wed Sep 08, 2021 9:45 pm

Re: No hit/collision on convexSweepTest using btBulletWorldImporter

Post by went4lunch »

That explains a lot! Thank you for that clear explanation!

So I tried using Bullet CCD by setting a valid value for the setCcdMotionThreshold and setCcdSweptSphereRadius but still didn't trigger a collision. Perhaps it's because there is no velocity calculated when I just move the object point to point (using setWorldTransform or object->setOrigin) and does not trigger the Bullet CCD? What is the proper way to move the object for the Bullet CCD? I don't need any dynamics (collision response, etc), just need collision checks.
You might be tempted to use a very generous bounding sphere for the proxy shape, however in my experience too-large proxies cause visible artifacts where the fast moving object may "stop" early before actually hitting its obstacle: the proxy hits first and somehow contributes contact manifold points which stop the real object too soon.
Yes, I'm very tempted to do so, but if visual representation is not needed but only to check for collision, would giving a generous bounding sphere still work then? Or did you mean it still contributes false contact manifold points that are not real collision, and therefore stop the object too soon?
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: No hit/collision on convexSweepTest using btBulletWorldImporter

Post by drleviathan »

It sounds like you are moving your object around kinematically: you set its position each step according to some external logic rather than allow the physics engine to integrate its motion forward in time. I don't believe CCD logic is triggered for objects that have been added to the World as kinematic, so you would want to make sure your object is flagged as dynamic, even if you are moving it in a kinematic fashion. But if you do that... your object's position might be bumped aside during step when it experiences a collision: this shouldn't be a problem if you override the transform + velocities every step AND if you only ever take one substep per step.

Even for truly kinematic objects it is recommended that you set their velocity to agree with their effective motion. Bullet will not integrate kinematic objects forward, but the contact points between two objects take velocities into account to compute the results and this makes for more correct collision responses for dynamic objects that come into contact with kinematic. If you are moving a dynamic object around in a kinematic way but you want CCD logic to kick in correctly then you must similarly set its velocity to agree with its effective motion.

I believe, based on the behavior I've seen, that CCD will add early contact points to the contact manifold based on where the sphere proxy hit, rather than where the real object hit. However, I have not verified this by examining the code or looking at the contact points very carefully. Hence, it is possible that CCD will add inexact contact points that do not represent how the true shape collides.

Perhaps what you could do for real-time performance is to set your CCD velocity threshold non-zero but very low so that it ALWAYS triggers, and take very large inexpensive timesteps forward... until you do collide at which point you could back-up and re-step at smaller timestep durations and do a binary search toward where the collision actually occurs. This would run fast most of the time but would slow down when you hit. It might be possible to ameliorate the cost across multiple steps by taking cheap predictive steps into the future to alert your logic there is a potential collision happening in the future in which case it should take shorter steps more often. I speculate here but do not know if such a strategy would be profitable.

For performance you should know: doing a relatively large sweep of a sphere through a dense triangle mesh static shape could be quite expensive. By "relatively large" I mean mean a sweep that spans several hundred or a few thousand potential triangles of the mesh. The fewer triangles the sweep might hit the better: a good reason to use smaller spheres and take shorter steps if your ground mesh is complicated.
went4lunch
Posts: 4
Joined: Wed Sep 08, 2021 9:45 pm

Re: No hit/collision on convexSweepTest using btBulletWorldImporter

Post by went4lunch »

I'll try with using a box convexshape for convexSweepTest and then perform discrete CD. A Box is closer to the actual shape we have. Tested it and yes convexSweepTest works now with a box shape. Will see if this will perform well. Your input has been a great help! Thank you so much!! :D
Post Reply