I think there is a bug in btSubsimplexConvexCast::calcTimeOfImpact(). I'm trying to use raycasting to generate some sample points on an object's surface, including the collision margin. Sometimes it produces a point which is obviously far removed from the surface.
After some debugging I notice that in those bad cases the hitpoint returned in the CastResult does not match the fraction (or lambda) by a long shot.
I think what is occurring is that the lambda value is not guaranteed to correspond with the closest values obtained from the simplexSolver. Lambda is always the last made estimate, but the best points gotten from the simplexSolver may be from another estimate.
In the case that I am seeing, the last iteration does a misstep (the ray is just skimming the surface, so numerically it's a bit nasty). This places lambda well away from the surface giving a bad fraction in the result, but simplexSolver->compute_points() returns the hit points from a previous much better estimate.
I'm not sure yet if this mismatch only occurs in some extreme cases, or if it almost always occurs but is hidden by successive lambdas tending to be similar as it converges.
---JvdL---
Possible bug in btSubsimplexConvexCast::calcTimeOfImpact
-
jarno
- Posts: 57
- Joined: Tue Mar 16, 2010 1:42 am
-
jarno
- Posts: 57
- Joined: Tue Mar 16, 2010 1:42 am
Re: Possible bug in btSubsimplexConvexCast::calcTimeOfImpact
Using btCollisionWorld::objectQuerySingle() instead of btCollisionWorld::rayTestSingle() avoids the problem in my particular instance, as it uses a different ray caster. But there appear to be a number of other places in the Bullet code which use btSubsimplexConvexCast.
---JvdL---
---JvdL---
-
Erwin Coumans
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
Re: Possible bug in btSubsimplexConvexCast::calcTimeOfImpact
This should only happen in extreme cases.
Can you provide a reproduction case, using one of the Bullet demos (ray start/end, and collision object involved)
Thanks,
Erwin
Can you provide a reproduction case, using one of the Bullet demos (ray start/end, and collision object involved)
Thanks,
Erwin
-
jarno
- Posts: 57
- Joined: Tue Mar 16, 2010 1:42 am
Re: Possible bug in btSubsimplexConvexCast::calcTimeOfImpact
Little test program which shoots rays along the -Z axis near the top of a cube at increasing Y values. It starts off okay, then the hit point rolls over the top, and when t == 0 (Y == 1) it suddenly jumps to the back well outside the bounding box. It get progressively worse until the fraction becomes larger than 1 or there is a genuine miss.
---JvdL---
Code: Select all
#include "btBulletDynamicsCommon.h"
#include <iostream>
int main(int argc, char* argv[])
{
// Create world with default collision handling
btDefaultCollisionConfiguration* collision_configuration = new btDefaultCollisionConfiguration();
btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collision_configuration);
btBroadphaseInterface* overlapping_pair_cache = new btDbvtBroadphase();
btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver();
btDiscreteDynamicsWorld* dynamics_world = new btDiscreteDynamicsWorld(dispatcher, overlapping_pair_cache, solver, collision_configuration);
// Create cube collision shape as convex hull
const btVector3 cube_points[8] = { btVector3( 0.5f, 0.5f, -0.5f), btVector3( 0.5f, -0.5f, -0.5f), btVector3(-0.5f, -0.5f, -0.5f), btVector3( 0.5f, 0.5f, 0.5f),
btVector3(-0.5f, -0.5f, 0.5f), btVector3(-0.5f, 0.5f, -0.5f), btVector3( 0.5f, -0.5f, 0.5f), btVector3(-0.5f, 0.5f, 0.5f) };
btConvexHullShape* cube_shape = new btConvexHullShape(&cube_points[0][0], 8);
cube_shape->setMargin(0.04f);
btCompoundShape* collisionshape = new btCompoundShape(false);
btTransform trans;
trans.setIdentity();
trans.setOrigin(btVector3(0, 0, 0));
collisionshape->addChildShape(trans, cube_shape);
// Create rigidbody with the cube collision shape, moved a bit off world origin
btRigidBody::btRigidBodyConstructionInfo construction_info(1, NULL, collisionshape);
construction_info.m_startWorldTransform.setIdentity();
construction_info.m_startWorldTransform.setOrigin(btVector3(0.0355311f, 0.451984f, 0.218113f));
btRigidBody* rigidbody = new btRigidBody(construction_info);
// Dump out bounding box
btVector3 aabb_min, aabb_max;
rigidbody->getAabb(aabb_min, aabb_max);
std::cout << "AABB: ";
std::cout << " (" << aabb_min[0] << ", " << aabb_min[1] << ", " << aabb_min[2] << ")";
std::cout << " (" << aabb_max[0] << ", " << aabb_max[1] << ", " << aabb_max[2] << ")" << std::endl;
std::cout << "Margin: " << cube_shape->getMargin() << std::endl;
// Shoot rays at the cube, near the top
for(int t = -32; t <= 32; t++)
{
std::cout << t << ": ";
btVector3 ray_from(0, 1 + t/4096.f, 2);
btVector3 ray_to = ray_from + btVector3(0, 0, -4);
std::cout << "(" << ray_from[0] << ", " << ray_from[1] << ", " << ray_from[2] << ")";
std::cout << " -> ";
std::cout << "(" << ray_to[0] << ", " << ray_to[1] << ", " << ray_to[2] << ") : ";
btTransform ray_from_trans;
ray_from_trans.setIdentity();
ray_from_trans.setOrigin(ray_from);
btTransform ray_to_trans;
ray_to_trans.setIdentity();
ray_to_trans.setOrigin(ray_to);
btCollisionWorld::ClosestRayResultCallback result_callback(ray_from, ray_to);
btCollisionWorld::rayTestSingle(ray_from_trans, ray_to_trans, rigidbody, collisionshape, construction_info.m_startWorldTransform, result_callback);
if(result_callback.hasHit())
{
std::cout << result_callback.m_closestHitFraction;
std::cout << " (" << result_callback.m_hitPointWorld[0] << ", " << result_callback.m_hitPointWorld[1] << ", " << result_callback.m_hitPointWorld[2] << ")" << std::endl;
}
else
{
std::cout << "Missed" << std::endl;
}
}
return 0;
}