No collisions with btHeightfieldTerrainShape?!

Post Reply
benadler
Posts: 8
Joined: Tue Mar 09, 2010 12:52 pm

No collisions with btHeightfieldTerrainShape?!

Post by benadler »

Hello!

I'm new to bullet and managed to get it working together with (bt)ogre. Things work generally fine, but I have a few problems:

There's a quadrotor helicopter being simulated, and after translating rotor speeds into thrust, it flies nicely through the world. My problem is that when I just let it fall, it won't ever collide with the btHeightfieldTerrainShape set up. For debugging purposes, I have already added a simple btStaticPlaneShape (the last 5 lines of the first listing, currently commented) and that does work just fine. Yes, I've read http://bulletphysics.org/Bullet/phpBB3/ ... php?t=4819 and although I'm not quite sure what transform he's talking about, I'm quite confident the heightfield isn't just offset:
2010-03-12 Physik.png
2010-03-12 Physik.png (307.09 KiB) Viewed 9425 times
This is how I set up the world:

Code: Select all

    //Bullet initialisation.
    mBtBroadphase = new btAxisSweep3(btVector3(-10000,-10000,-10000), btVector3(10000,10000,10000), 1024);
    mBtCollisionConfig = new btDefaultCollisionConfiguration();
    mBtDispatcher = new btCollisionDispatcher(mBtCollisionConfig);
    mBtSolver = new btSequentialImpulseConstraintSolver();

    mBtWorld = new btDiscreteDynamicsWorld(mBtDispatcher, mBtBroadphase, mBtSolver, mBtCollisionConfig);
    mBtWorld->setGravity(btVector3(0,-9.8,0));

    //----------------------------------------------------------
    // Debug drawing!
    //----------------------------------------------------------

    mBtDebugDrawer = new BtOgre::DebugDrawer(mOgreWidget->sceneManager()->getRootSceneNode(), mBtWorld);
    mBtWorld->setDebugDrawer(mBtDebugDrawer);
    mBtDebugDrawer->setDebugMode(1);

    //----------------------------------------------------------
    // Vehicle!
    //----------------------------------------------------------
    qDebug() << "Vehicle::Vehicle(): creating vehicle";
    mVehicleEntity = mOgreWidget->sceneManager()->createEntity("vehicleEntity", "quad.mesh");
    // "vehicleNode" is fixed, used in ogrewidget.cpp
    mVehicleNode = mOgreWidget->sceneManager()->getRootSceneNode()->createChildSceneNode("vehicleNode", Ogre::Vector3(0,10,0), Ogre::Quaternion::IDENTITY);
    mVehicleNode->attachObject(mVehicleEntity);

    //Create shape.
    BtOgre::StaticMeshToShapeConverter converter(mVehicleEntity);
    mVehicleShape = converter.createConvex();

    // Reduce vertices (20k to maybe 100?)
    btShapeHull* hull = new btShapeHull(mVehicleShape);
    btScalar margin = mVehicleShape->getMargin();
    hull->buildHull(margin);
    mVehicleShape = new btConvexHullShape((btScalar*)hull->getVertexPointer(), hull->numVertices()/*, sizeof(btVector3)*/);

    //Calculate inertia.
    btScalar mass = 1.5;
    btVector3 inertia;
    mVehicleShape->calculateLocalInertia(mass, inertia);

    //Create BtOgre MotionState (connects Ogre and Bullet).
    BtOgre::RigidBodyState *vehicleState = new BtOgre::RigidBodyState(mVehicleNode);

    //Create the Body.
    mVehicleBody = new btRigidBody(mass, vehicleState, mVehicleShape, inertia);
//    mVehicleBody->setCollisionFlags(mVehicleBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK );

    mVehicleBody->setDamping(.5, .9);

//    mVehicleBody->setActivationState(ISLAND_SLEEPING);
    mBtWorld->addRigidBody(mVehicleBody/*, COL_VEHICLE, COL_GROUND*/);
//    mVehicleBody->setActivationState(ISLAND_SLEEPING);

    //----------------------------------------------------------
    // Load terrain!
    //----------------------------------------------------------
   std::string terrainFileStr = "terrain.cfg";

   Ogre::DataStreamPtr configStream = Ogre::ResourceGroupManager::getSingleton().openResource(terrainFileStr, Ogre::ResourceGroupManager::getSingleton().getWorldResourceGroupName());
   Ogre::ConfigFile config;
   config.load(configStream);

   Ogre::String widthStr = config.getSetting("PageSize");
   int width = atoi(widthStr.c_str());

   Ogre::String imgFile = config.getSetting("Heightmap.image");

   Ogre::Image* heightmap = new Ogre::Image();
   heightmap->load(imgFile, Ogre::ResourceGroupManager::getSingleton().getWorldResourceGroupName());

   qDebug() << "Vehicle::Vehicle(): image buffer size" << heightmap->getSize();

   Ogre::String maxHeightStr = config.getSetting("MaxHeight");
   btScalar maxHeight = atof(maxHeightStr.c_str());
   btScalar heightScale = maxHeight / 256;

   // This code for the localScaling is taken directly from the TerrainSceneManager, adapted to a btVector3
   btVector3 localScaling(1, 1, 1);
   localScaling.setX(atof(config.getSetting("PageWorldX").c_str()) / (width -1));
   localScaling.setZ(atof(config.getSetting("PageWorldZ").c_str()) / (width -1));

   // And now, we actually call Bullet. heightmap needs to be on the heap, as bullet does not copy it.
   mGroundShape = new btHeightfieldTerrainShape(width, width, heightmap->getData(), heightScale, 0, maxHeight, 1, PHY_UCHAR, false);
   mGroundShape->setLocalScaling(localScaling);

   // All thats left is to line up the Ogre::SceneNode with the btHeightfieldTerrainShape.
   // We have to do it this way because of differences in how Bullet and Ogre orient the shapes.
   // In Ogre, the terrain's top left corner is at (0, 0, 0) in the local TransformSpace
   // In Bullet, not only is the center of the btHeighfield terrrain shape at (0, 0, 0), but from
   //      what I can tell, its immovable.
   btVector3 min, max;
   mGroundShape->getAabb(btTransform::getIdentity(), min, max);
   Ogre::SceneNode *sNode = mOgreWidget->sceneManager()->getSceneNode("Terrain");
   sNode->setPosition(BtOgre::Convert::toOgre(min));

   // Finally, create your btMotionState, and btRigidBody, and all the rigid body to the physics world.
   BtOgre::RigidBodyState* terrainState = new BtOgre::RigidBodyState(sNode, btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 0, 0)));
   mGroundBody = new btRigidBody(0, terrainState, mGroundShape, btVector3(0, 0, 0));
//   mGroundBody->setCollisionFlags(mGroundBody->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT);
   mBtWorld->addRigidBody(mGroundBody, COL_GROUND, COL_NOTHING);

   // Debug, add a plane like the tutorial says
//   btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),1);
//   btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,-1,0)));
//   btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(0,groundMotionState,groundShape,btVector3(0,0,0));
//   btRigidBody* groundRigidBody = new btRigidBody(groundRigidBodyCI);
//   mBtWorld->addRigidBody(groundRigidBody);
and this is what I do each step (without any forces applied, it just falls through the terrain):

Code: Select all

    const int simulationTime = mSimulator->getSimulationTime(); // milliseconds
    const btScalar deltaS = (simulationTime - mTimeOfLastUpdate) / 1000.0f; // elapsed time since last call in seconds
    const int maxSubSteps = 100;
    const btScalar fixedTimeStep = 1.0 / 60.0;
    qDebug() << "Vehicle::slotUpdatePhysics(): stepping physics, time is" << simulationTime << "delta" << deltaS;

    mVehicleBody->applyDamping(deltaS);

    Q_ASSERT(deltaS < maxSubSteps * fixedTimeStep); // http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World
    mBtWorld->stepSimulation(deltaS, maxSubSteps, fixedTimeStep);

    mBtDebugDrawer->step();

    mTimeOfLastUpdate = simulationTime;
    mOgreWidget->update();
My questions:

- Why doesn't the object collide with the heightfield while it does collide with the simple btStaticPlaneShape?

- Sometimes when I start the simulation, my vehicle-object doesn't move (e.g. fall without any forces except gravity applied) at all, although it should. When I restart the program and click on start again, it works. I don't need perfect determinism, but this is really strange. How can I debug this?

Thanks for your help!
ben
benadler
Posts: 8
Joined: Tue Mar 09, 2010 12:52 pm

Re: No collisions with btHeightfieldTerrainShape?!

Post by benadler »

Excuse me bumping my own question, but I'm really stuck. I've tried both 2.76 and trunk, both (mis)behave in the same way.

Do I need to btRigidBody::setCollisionFlags() for collision with a heightfield? Do I have to setActivationState()? Is it necessary to specify group and mask for addRigidBody()? I tried all of that, but not in all combinations, as collision with the btStaticPlaneShape works fine.

Is it possible to move a btHeightfieldTerrainShape in Bullet instead of moving the terrain in Ogre?

How would you try to debug this?
Kukanani
Posts: 25
Joined: Sat Feb 21, 2009 5:08 am

Re: No collisions with btHeightfieldTerrainShape?!

Post by Kukanani »

I'm having the same problem as you. I'm doing something very similar...trying all kind of different terrain initialization settings...I will post back if I learn anything.
benadler
Posts: 8
Joined: Tue Mar 09, 2010 12:52 pm

Re: No collisions with btHeightfieldTerrainShape?!

Post by benadler »

Kukanani,

just in case you're still stuck: I've changed a lot of stuff and ported my app to use Ogres new terrain. Except for slight differences in tesselation, things work fine now.

Have a look at http://www.ogre3d.org/forums/viewtopic.php?t=58756

cheers,
ben
benelot
Posts: 350
Joined: Sat Jul 04, 2015 10:33 am
Location: Bern, Switzerland
Contact:

Re: No collisions with btHeightfieldTerrainShape?!

Post by benelot »

I know it is very unfortunate to dig up such an old post, but I would really be interested in the code on how to make Ogre3D work with a Bullet terrain. I would be happy to start from the implementation you showed on the Ogre Forums. Would you be able to help me out here?
Post Reply