Possible bug in btSubsimplexConvexCast::calcTimeOfImpact

User avatar
jarno
Posts: 57
Joined: Tue Mar 16, 2010 1:42 am

Possible bug in btSubsimplexConvexCast::calcTimeOfImpact

Post by jarno »

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---
User avatar
jarno
Posts: 57
Joined: Tue Mar 16, 2010 1:42 am

Re: Possible bug in btSubsimplexConvexCast::calcTimeOfImpact

Post by jarno »

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---
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: Possible bug in btSubsimplexConvexCast::calcTimeOfImpact

Post by Erwin Coumans »

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
User avatar
jarno
Posts: 57
Joined: Tue Mar 16, 2010 1:42 am

Re: Possible bug in btSubsimplexConvexCast::calcTimeOfImpact

Post by jarno »

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.

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;
}
---JvdL---