Collision Physics with Terrain

A place for users of OGRE to discuss ideas and experiences of utilitising OGRE in their games / demos / applications.
Post Reply
dunderwood
Gnoblar
Posts: 7
Joined: Mon Feb 10, 2014 11:50 pm
Location: Raleigh, NC

Collision Physics with Terrain

Post by dunderwood »

I am currently working on working with collision detection in terrain. The terrain that I am using is coming from a .scene format. I am using Bullet for a physics library, but do not wish to use OgreBullet, as it seems to be dead. My current approach is to do the following:

First, get the location of the entity with entity->getPosition(). This vector is then used to get the height of the terrain at the position with terrain->getHeightAtWorldPosition(position). The terrain is coming from when I am loading the .scene file and getting the terrain at the position from the TerrainGroup that comes with loading the .scene file. I then plan to create a plane or something similar in bullet and then proceed with the normal way of doing physics with the physics engine.

However, this seems overly complicated, as it would be just as easy to do all the collisions with a RaySceneQuery at this point. It also seems like this technique would have some issues with uneven terrain. I also plan to manage collision detection for .bsp maps as well at some point, meaning I would have to redesign this for that type of map, which isn't managed by the whole terrain system as far as I know.

Anyone have any suggestions or alternate ways I could do this? I would like to integrate bullet as it seems to be a fairly reliable physics engine, although I plan to rewrite parts of it or write my own physics engine at some point. I also plan to allow different map types in my final game, so I would like to make the technique as flexible as possible for the map type.

EDIT: I have now thought of somehow processing the entire terrain into an object in bullet during the loading of the scene, and hopefully the broadphase in bullet will stop unnecessary computation. Does anyone have any comments on this technique or suggestions of how to do it (I know how to get the height at a specific point, but not much else)?
User avatar
Herb
Orc
Posts: 412
Joined: Thu Jun 04, 2009 3:21 am
Location: Kalamazoo,MI
x 38

Re: Collision Physics with Terrain

Post by Herb »

Yeah, I would agree on OgreBullet. Take a look at BtOgre It's a really thin wrapper on Bullet, really just providing some helper methods on type conversions and such. As for terrain, here are some snippets on a game I was developing that might help. I scratched my head for a bit till I worked out the terrain integration too.

Okay, in my main game state start-up, here is my physics (btOgre setup). Notice I'm using a DotSceneLoader too.

Code: Select all

    // setup Physics engine
    
    /// @todo have no idea if this is the right configuration....what configuration would be better?
    mBroadphase = new btDbvtBroadphase();
    mCollisionConfig = new btDefaultCollisionConfiguration();
    mDispatcher = new btCollisionDispatcher(mCollisionConfig);
    mSolver = new btSequentialImpulseConstraintSolver();    
    
    mPhyWorld = new btDiscreteDynamicsWorld(mDispatcher, mBroadphase, mSolver, mCollisionConfig);
    
    /// @todo what is the best gravity? Using setting from the demo
    mPhyWorld->setGravity(btVector3(0,-9.8,0));  // hmm... another demo has y being 100...
    
    mPhyDebugDraw = new BtOgre::DebugDrawer(mSceneMgr->getRootSceneNode(), mPhyWorld);
    mPhyWorld->setDebugDrawer(mPhyDebugDraw);    

    // load all the height data (each terrain page) as a static mesh for bullet to create as a static geometry mesh
    Ogre::TerrainGroup* group = mDotSceneLoader->getTerrainGroup();
    
    Ogre::TerrainGroup::TerrainIterator terrainIterator = mDotSceneLoader->getTerrainGroup()->getTerrainIterator();
    
    while(terrainIterator.hasMoreElements())
    {
        Ogre::Terrain* terrain = terrainIterator.getNext()->instance;
   
        createHeightfieldShape(terrain->getSize(), 
                               terrain->getHeightData(),
                               terrain->getMinHeight(),
                               terrain->getMaxHeight(),
                               terrain->getPosition(),
                               terrain->getWorldSize()/(terrain->getSize()-1)
                              );        
    }    
Here is that createHeightfieldShape method reference in the above method

Code: Select all

void ActiveGameState::createHeightfieldShape(int size, float* data, const Ogre::Real& minHeight, const Ogre::Real& maxHeight, const Ogre::Vector3& position, const Ogre::Real& scale)
{
   // Convert height data in a format suitable for the physics engine
   float *terrainHeights = new float[size * size];
   assert(terrainHeights != 0);

   for (int i = 0; i < size; i++)
   {
      memcpy(terrainHeights + size * i, data + size * (size - i - 1), sizeof(float) * size);
   }

   btScalar heightScale = 1.f;
   
   btVector3 localScaling(scale, heightScale, scale);
 
   btHeightfieldTerrainShape *terrainShape = new btHeightfieldTerrainShape(size, size, terrainHeights, 1/*ignore*/, minHeight, maxHeight, 1, PHY_FLOAT, true);
   terrainShape->setUseDiamondSubdivision(true);
   terrainShape->setLocalScaling(localScaling);

   //Create Rigid Body using 0 mass so it is static
   btRigidBody *body = new btRigidBody(BT_LARGE_FLOAT, new btDefaultMotionState(), terrainShape);
   body->setFriction(0.8f);
   body->setHitFraction(0.8f);
   body->setRestitution(0.6f);
   body->getWorldTransform().setOrigin(btVector3(position.x, position.y + (maxHeight - minHeight) / 2, position.z));
   body->getWorldTransform().setRotation(BtOgre::Convert::toBullet(Ogre::Quaternion::IDENTITY));
   body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT);

   mPhyWorld->addRigidBody(body);
}
Then in the my active game state's frameStarted method (tied to the OgreFrameListener), I do:

Code: Select all

    //Update Bullet world
    mPhyWorld->stepSimulation(evt.timeSinceLastFrame);
    mPhyWorld->debugDrawWorld();

    //Shows debug if F3 key down.
    mPhyDebugDraw->setDebugMode(mInputMgr->getKeyboard()->isKeyDown(OIS::KC_F3));
    mPhyDebugDraw->step();
Hope that helps and gives you a starting point at least! :)
dunderwood
Gnoblar
Posts: 7
Joined: Mon Feb 10, 2014 11:50 pm
Location: Raleigh, NC

Re: Collision Physics with Terrain

Post by dunderwood »

Thanks! I haven't gotten to poke around the code much yet, but hopefully I will later today, and it looks like it will help at least a bit. I looked up BtOgre, and the latest commit was about a year ago. What version of Ogre and Bullet have you used it with? Additionally, at first glance of that code, there isn't anything that is using btOgre. Is that correct? EDIT: Nevermind, just saw mPhyDebugDraw.

Also, I don't know how recent this code is, but in the first code snippet where you set the gravity and there's a comment about another demo being 100, typical gravity is the -9.8 if you are scaling the game world to the real world. The 100 would be if you were using some soft of weird scaling system. In addition, if the value was actually positive 100, the other demo either had the y-axis reversed or was using some sort of weird constant system for the gravity. I hope this may have helped you with that point if you were still wondering about that bit.

EDIT: I'm messing with the code a bit now. It was working fine, until I got to linking with BtOgre, where I get the following errors:

Code: Select all

/home/danielunderwood/Documents/btOgreBuilds/03102014/libBtOgre.a(BtOgre.cpp.o): In function `BtOgre::VertexIndexToShape::createBox()':
BtOgre.cpp:(.text+0x1291): undefined reference to `btBoxShape::btBoxShape(btVector3 const&)'
/home/danielunderwood/Documents/btOgreBuilds/03102014/libBtOgre.a(BtOgre.cpp.o): In function `BtOgre::VertexIndexToShape::createCylinder()':
BtOgre.cpp:(.text+0x13ff): undefined reference to `btCylinderShapeX::btCylinderShapeX(btVector3 const&)'
/home/danielunderwood/Documents/btOgreBuilds/03102014/libBtOgre.a(BtOgre.cpp.o): In function `BtOgre::VertexIndexToShape::createConvex()':
BtOgre.cpp:(.text+0x14e0): undefined reference to `btConvexHullShape::btConvexHullShape(float const*, int, int)'
/home/danielunderwood/Documents/btOgreBuilds/03102014/libBtOgre.a(BtOgre.cpp.o): In function `BtOgre::VertexIndexToShape::createTrimesh()':
BtOgre.cpp:(.text+0x15df): undefined reference to `btTriangleMesh::btTriangleMesh(bool, bool)'
BtOgre.cpp:(.text+0x17d1): undefined reference to `btTriangleMesh::addTriangle(btVector3 const&, btVector3 const&, btVector3 const&, bool)'
/home/danielunderwood/Documents/btOgreBuilds/03102014/libBtOgre.a(BtOgre.cpp.o): In function `BtOgre::VertexIndexToShape::createCapsule()':
BtOgre.cpp:(.text+0x19cf): undefined reference to `btCapsuleShape::btCapsuleShape(float, float)'
BtOgre.cpp:(.text+0x1a40): undefined reference to `btCapsuleShapeX::btCapsuleShapeX(float, float)'
BtOgre.cpp:(.text+0x1a99): undefined reference to `btCapsuleShapeZ::btCapsuleShapeZ(float, float)'
/home/danielunderwood/Documents/btOgreBuilds/03102014/libBtOgre.a(BtOgre.cpp.o): In function `BtOgre::AnimatedMeshToShapeConverter::createAlignedBox(unsigned char, Ogre::Vector3 const&, Ogre::Quaternion const&)':
BtOgre.cpp:(.text+0x2e49): undefined reference to `btBoxShape::btBoxShape(btVector3 const&)'
/home/danielunderwood/Documents/btOgreBuilds/03102014/libBtOgre.a(BtOgre.cpp.o): In function `BtOgre::AnimatedMeshToShapeConverter::createOrientedBox(unsigned char, Ogre::Vector3 const&, Ogre::Quaternion const&)':
BtOgre.cpp:(.text+0x355f): undefined reference to `btBoxShape::btBoxShape(btVector3 const&)'
BtOgre itself was built fine, so I'm assuming that it's linking to Bullet successtully. I've looked through the source for bullet and the constructors with the given overloads are still there. I've even tried including the headers for the individual shapes.

Any suggestions?

EDIT 2: I was able to fix the referencing problem by just integrating BtOgre's source into the code for my project. It would be nice to know what was going on there, though.

EDIT 3: Is there any effect on your FPS when you press F3 for the debug draw? Mine is dropping from about 900 to less than 1.
User avatar
Herb
Orc
Posts: 412
Joined: Thu Jun 04, 2009 3:21 am
Location: Kalamazoo,MI
x 38

Re: Collision Physics with Terrain

Post by Herb »

Yeah, I never did much testing on the setup of Bullet (ie what gravity and such to set). It really was me trying to get all the terrain data loaded into Bullet, which works. As for the debug draw, it is a huge FPS penalty if you have a lot of terrain. It's because it creates manual objects to render to show all the terrain that Bullet is keeping track of. I think my test map had 4 terrain pages that were not that big and had limited vertex counts, so it wasn't as bad as you're seeing... If you're terrain is huge, you might need to modify how the debug draw is happening if you want to still see it. It's not really that complicated. Glad this helped you get going with Bullet. :)
Post Reply