Mesh Bounding Box Problem

crancran

06-11-2011 18:03:44

So I decided I would play with a few mesh files that shipped with Ogre, namely robot and ninja. In both cases, it appears that after I obtain the bounding box, it seems that the top of the bounding box is at the center of the mesh's body. This is creating problems when I add an entity to the scene because they immediately collide with the ground. Here is what I am doing:


void PhysicsSubSystem::OnSpawnTest(GameEvent& e) {
// Stores the size of the bounding box
Ogre::Vector3 size = Ogre::Vector3::ZERO;

// Our test should spawn on the ground to avoid any collision
// problems (since bound box problem, spawning higher)
Ogre::Vector3 pos = Ogre::Vector3(0, 10, 0);

Ogre::SceneManager* pSceneManager = RenderSubSystem::getSingletonPtr()->getSceneManager();
Ogre::SceneNode* pNode = pSceneManager->getRootSceneNode()->createChildSceneNode();
Ogre::Entity* pEntity = pSceneManager->createEntity("robot.mesh");
pEntity->setCastShadows(true);
pNode->showBoundingBox(true); // displays the scene node's box
pNode->attachObject(pEntity);

// Get the AABB of the attached entity
Ogre::AxisAlignedBox bb = pEntity->getBoundingBox();
size = bb.getSize();
size *= 0.5f; // same as dividing by 2 (faster on CPU)
size *= 0.95f;

// Create the Collision shape
OgreBulletCollisions::BoxCollisionShape* pShape = new OgreBulletCollisions::BoxCollisionsShape(size);
OgreBulletDynamics::RigidBody* pRigidBody = new OgreBulletDynamics::RigidBody(pNode->getName() + "_rigidBody", m_pWorld);
pRigidBody->setShape(pNode, pShape, 0.0f, 0.6f, 1.0f, pos);
pRigidBody->setLinearVelocity(Ogre::Vector3::ZERO);
pRigidBody->setDebugShape(true);

// Send event that node spawned
EventSubSystem::getSingletonPtr()->notify(SpawnEvent(pNode->getName(),pNode));
}


If I disable physics and set the starting position at Vector3(0,0,0), then the mesh is perfectly aligned with the ground; however upon enabling physics, the node is bounced high into the air because the node's physics bounding box appears to be shifted 1/2 way down the mesh's body, thus creating a lot of "empty space" below the mesh's feet which obviously intersect with the ground using Vector3(0,0,0), causing it to bounce. What can I do in order to account or fix the problem?

dermont

07-11-2011 02:16:44

Try a CompoundCollisionShape with an offset equal to the centre of the entity's bounding box. See the following link.

viewtopic.php?f=12&t=13705

OgreBulletCollisions::BoxCollisionShape *sceneBoxShape = new OgreBulletCollisions::BoxCollisionShape(size);
OgreBulletCollisions::CompoundCollisionShape* comShape = new OgreBulletCollisions::CompoundCollisionShape();
comShape->addChildShape(sceneBoxShape, Ogre::Vector3(0,-0.7,-1.3), Ogre::Quaternion(1,0,0,0));

OgreBulletDynamics::RigidBody *defaultBody = new OgreBulletDynamics::RigidBody("defaultBoxRigid" + Ogre::StringConverter::toString(*m_nNumEntitiesInstanced),m_World);
defaultBody->setShape(node,
comShape,
0.6f, // dynamic body restitution
0.8f, // dynamic body friction
8.0f, // dynamic bodymass
position, // starting position of the box
direction);// orientation of the box

crancran

07-11-2011 20:50:48

I am still noticing strange behavior.

First, if I don't specify Y=560.5 for when I create the house, it immediately bounces into the air. If I recall the AABB has a max Y of 576 and a min of -566. Therefore this seems to be dealing with applying the offset as directed, but how can I change the logic to account for this offset so I can specify for it to spawn at Y=0 instead?

Secondly, the ninja avatar spawns at what appears to be ~ Y=0 and then proceeds to elevate off the ground.

Any ideas on my code below as to what it is I am doing incorrectly? I am at a loss.


// create bodies
void PhysicsTest::createRigidBody(String name, Entity* pEntity, SceneNode* pNode, btScalar mass)
{

if(!pEntity) return;
if(!pNode) return;

btTransform transform;
transform.setIdentity();

// Get the AABB of the pentity
AxisAlignedBox aabb = pEntity->getWorldBoundingBox(true);

// Create box shape based on AABB
btVector3 halfExtents(OgreToBullet(aabb.getSize() * 0.95f));
btCollisionShape* pBox = new btBoxShape(halfExtents);

// Perform transformation
btTransform localTrans;
localTrans.setOrigin(ogreToBt(aabb.getCenter()));
localTrans.setRotation(btQuaternion(0,0,0,1));

// Create compound object
btCompoundShape* pComp = new btCompoundShape(false);
pComp->addChildShape(localTrans, pBox);

btVector3 localInertia;

// if the object has mass, apply inertia
if(mass != 0.f)
pComp->calculateLocalInertia(mass, localInertia);

// Define motion state
transform.setOrigin(ogreToBt(pNode->getPosition()));
transform.setRotation(ogreToBt(pNode->getOrientation()));

// OgreMotionState is just like OgreBullet except initial
// position gets stored.
OgreMotionState* pState = new OgreMotionState(transform, pNode);


// Create rigid body
btRigidBody::btRigidBodyConstructionInfo rbinfo(mass, pState, pComp, localInertia);
btRigidBody* pBody = new btRigidBody(rbinfo);

// apply some standard settings
pBody->setRestitution(0.0);
pBody->setFriction(0.00);
pBody->setLinearVelocity(btVector3(0,0,0));

// this should prevent collisions from rotating around axis??
pBody->setInvInertiaDiagLocal(btVector3(0,0,0));
pBody->updateInertiaTensor();

// store shape references
addShape(pComp);
addShape(pBox);

// provide body to bullet
addRigidBody(pBody);
}


// create ground
void PhysicsTest::createGround()
{
// make a rock wall on floor
Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0);
Ogre::MeshManager::getSingleton().createPlane("ground", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 15000, 15000, 20, 20, true, 1, 5, 5, Ogre::Vector3::UNIT_Z);
Ogre::Entity* pEntity = getSceneManager()->createEntity("GroundEntity", "ground");
Ogre::SceneNode* pNode = getRootSceneNode()->createChildSceneNode();
pNode->attachObject(pEntity);
pNode->setPosition(0,0,0);
pEntity->setMaterialName("Examples/Rockwall");
pEntity->setCastShadows(false);

// add some light to the ground
Ogre::Light* light = pManager->createLight("Light1");
light->setType(Ogre::Light::LT_POINT);
light->setPosition(Ogre::Vector3(250, 150, 250));
light->setDiffuseColour(Ogre::ColourValue::White);
light->setSpecularColour(Ogre::ColourValue::White);

//*********** BULLET PHYSICS APPLICATION TO GROUND ****************//

btTransform transform;
transform.setIdentity();
transform.setOrigin(btVector3(0, -1, 0));
btScalar mass(0.f); // is static
btVector3 localInertia(0, 0, 0);

btCollisionShape* pGround = m_pBullet->createBoxShape(15000, 1, 15000);
if(mass != 0.f) pGround->calculateLocalInertia(mass, localInertia);

btDefaultMotionState* pState = new btDefaultMotionState(transform);

btRigidBody::btRigidBodyConstructionInfo rbinfo(mass, pState, pGround, localInertia);
btRigidBody* pBody = new btRigidBody(rbinfo);
pBody->setRestitution(0); // dont want objects to bounce off it
pBody->setFriction(8);

addRigidBody(pBody);
}

// create our house
void PhysicsTest::createHouse()
{
Ogre::SceneNode* pNode = getRootSceneNode()->createChildSceneNode("House");
pNode->setPosition(-100, 560.5, 0);

Ogre::Entity* pEntity = getSceneManager()->createEntity("House_Mesh", "tudorhouse.mesh");
pNode->attachObject(pEntity);
pNode->showBoundingBox(true);
pNode->_update(true,true);

createRigidBody("TudorHouse", pEntity, pNode, 0);
}

// create our character
void PhysicsTest::createAvatar()
{
Ogre::SceneNode* pNode = getRootSceneNode()->createChildSceneNode("Avatar");
pNode->setPosition(400, 0, 100);

Ogre::Entity* pEntity = getSceneManager()->createEntity("Ninja_Mesh", "ninja.mesh");
pNode->attachObject(pEntity);
pNode->showBoundingBox(true);
pNode->_update(true,true);

createRigidBody("Ninja", pEntity, pNode, 0.5);
}

// initialize bullet library
void PhysicsTest::initBullet()
{
Ogre::Vector3 worldMin(-15000, -15000, -15000);
Ogre::Vector3 worldMax( 15000, 15000, 15000);

m_pConfig = new btDefaultCollisionConfiguration();
m_pDispatcher = new btCollisionDispatcher(m_pConfig);
m_pSolver = new btSequentialImpulseConstraintSolver();

btVector3 min(btScalar(worldMin.x),btScalar(worldMin.y),btScalar(worldMin.z));
btVector3 max(btScalar(worldMax.x),btScalar(worldMax.y),btScalar(worldMax.z));
m_pAxisSweep = new btAxisSweep3(min,max);

m_pBroadphase = new btDbvtBroadphase();

m_pWorld = new btDiscreteDynamicsWorld(m_pDispatcher, m_pAxisSweep, m_pSolver, m_pConfig);
m_pWorld->setGravity(0,-9.81,0);
}

void PhysicsTest::addRigidBody(btRigidBody* pBody)
{
m_pWorld->addRigidBody(pBody);
}

// game loop trigger
bool PhysicsTest::update(double delta)
{
// delta is always 0.166667 for fixed time step
m_pWorld->stepSimulation(delta);
}

// setup test case
void PhysicsTest::setup()
{
initOgreFramework();
initBullet();

createGround();
createHouse();
createAvatar();
}

dermont

08-11-2011 06:29:02

Hi, you don't appear to be using OgreBullet, nevertheless I think your problem is:
- with your shapes and halfExtents - you should be using aabb.getHalfSize()
- your transform origin for your compound shape (that was my fault saying the offset is equal to the centre of the entity's bounding box).

For your house mesh:

void createRigidBody2(String name, Entity* pEntity, SceneNode* pNode, btScalar mass)
{
if(!pEntity) return;
if(!pNode) return;
btTransform transform;
transform.setIdentity();

AxisAlignedBox aabb = pEntity->getWorldBoundingBox(true);
btVector3 halfExtents(OgreToBullet(aabb.getHalfSize()));
btCollisionShape* pBox = new btBoxShape(halfExtents);

btTransform localTrans;
transform.setOrigin(OgreToBullet(pNode->getPosition()));
transform.setRotation(ogreToBt(pNode->getOrientation()));

// OgreMotionState is just like OgreBullet except initial
// position gets stored.
OgreMotionState* pState = new OgreMotionState(transform, pNode);
btVector3 localInertia;
if(mass != 0.f)
pBox->calculateLocalInertia(mass, localInertia);

// Create rigid body
btRigidBody::btRigidBodyConstructionInfo rbinfo(mass, pState, pBox, localInertia);
btRigidBody* pBody = new btRigidBody(rbinfo);

// store shape references
addShape(pBox);

addRigidBody(pBody);
}


For your ninja mesh:

// create bodies
void createRigidBody(String name, Entity* pEntity, SceneNode* pNode, btScalar mass)
{

if(!pEntity) return;
if(!pNode) return;
btTransform transform;
transform.setIdentity();

AxisAlignedBox aabb = pEntity->getWorldBoundingBox(true);
btVector3 halfExtents(OgreToBullet(aabb.getHalfSize()));
btCollisionShape* pBox = new btBoxShape(halfExtents);

// Perform transformation
btTransform localTrans;
localTrans.setOrigin(btVector3(0.0,aabb.getHalfSize().y,0.0));
localTrans.setRotation(btQuaternion(0,0,0,1));

// Create compound object
btCompoundShape* pComp = new btCompoundShape(false);
pComp->addChildShape(localTrans, pBox);

btVector3 localInertia;

// if the object has mass, apply inertia
if(mass != 0.f)
pComp->calculateLocalInertia(mass, localInertia);

// Define motion state
transform.setOrigin(OgreToBullet(pNode->getPosition()));
transform.setRotation(ogreToBt(pNode->getOrientation()));

// OgreMotionState is just like OgreBullet except initial
// position gets stored.
OgreMotionState* pState = new OgreMotionState(transform, pNode);

// Create rigid body
btRigidBody::btRigidBodyConstructionInfo rbinfo(mass, pState, pComp, localInertia);
btRigidBody* pBody = new btRigidBody(rbinfo);

// apply some standard settings
pBody->setRestitution(0.0);
pBody->setFriction(0.00);
pBody->setLinearVelocity(btVector3(0,0,0));

// this should prevent collisions from rotating around axis??
pBody->setInvInertiaDiagLocal(btVector3(0,0,0));
pBody->updateInertiaTensor();

// store shape references
addShape(pComp);
addShape(pBox);

// provide body to bullet
addRigidBody(pBody);
}


If you have a complete example of your program it would be easier to test. You should also test your application with your DebugDrawer to resolve issues such as the above.

There is a more complete character demo here.
http://codefreax.org/tutorials/view/id/3

visu4241

18-04-2013 06:05:41

HI,..I use getSize() on bounding box object but it gives the answer as (0,0,0). please help me on this.

AlexeyKnyshev

18-04-2013 14:27:47

HI,..I use getSize() on bounding box object but it gives the answer as (0,0,0). please help me on this.

So, it seems to be zero box. Look through you code, there is some problems.