OGRE Wiki
Support and community documentation for Ogre3D
Ogre Forums
ogre3d.org
Log in
Username:
Password:
CapsLock is on.
Remember me (for 1 year)
Log in
Home
Tutorials
Tutorials Home
Basic Tutorials
Intermediate Tutorials
Mad Marx Tutorials
In Depth Tutorials
Older Tutorials
External Tutorials
Cookbook
Cookbook Home
CodeBank
Snippets
Experiences
Ogre Articles
Libraries
Libraries Home
Alternative Languages
Assembling A Toolset
Development Tools
OGRE Libraries
List of Libraries
Tools
Tools Home
DCC Tools
DCC Tutorials
DCC Articles
DCC Resources
Assembling a production pipeline
Development
Development Home
Roadmap
Building Ogre
Installing the Ogre SDK
Setting Up An Application
Ogre Wiki Tutorial Framework
Frequently Asked Questions
Google Summer Of Code
Help Requested
Ogre Core Articles
Community
Community Home
Projects Using Ogre
Recommended Reading
Contractors
Wiki
Immediate Wiki Tasklist
Wiki Ideas
Wiki Guidelines
Article Writing Guidelines
Wiki Styles
Wiki Page Tracker
Ogre Wiki Help
Ogre Wiki Help Overview
Help - Basic Syntax
Help - Images
Help - Pages and Structures
Help - Wiki Plugins
Toolbox
Freetags
Categories
List Pages
Structures
Trackers
Statistics
Rankings
List Galleries
Ogre Lexicon
Comments
History: OgreBullet Tutorial 2
View page
Source of version: 4
(current)
This tutorial is entirely depending on the previous tutorial. We will use the project that was created there. --- Open the empty project (which is not completely empty, by the way) that you created last time and run it. You can see the Ogre head, I suppose. But, it doesn't matter now. Let's start coding! We won't change ''OgreBullet_Collision_test.cpp'' so you can close it if you want. Open ''OgreBullet_Collision_test.h''. From now on everything happens here. ''Notes:'' ''- You can split it to .h and .cpp file if you like. It's not a big program so I won't :)'' ''- I won't use namespaces, so you can see which classes contain which function.'' !Coding Part First of all we need this header to be able to use OgreBullet: {CODE(wrap="1", colors="c++")} #include "OgreBulletDynamicsRigidBody.h"{CODE} Now change the constructor of your ''FrameListener'' (insert two extra fields): {CODE(wrap="1", colors="c++")} OgreBullet_Collision_testFrameListener( SceneManager *sceneMgr, RenderWindow* win, Camera* cam, Vector3 &gravityVector, AxisAlignedBox &bounds) : ExampleFrameListener(win, cam), mSceneMgr(sceneMgr){CODE} The gravityVector defines the gravity in our example. I thought ''bounds'' defined the bounds where Bullet is active, but it seems that bounds has no effect. Anyway, we need it :) Find ''createFrameListener(void)'' function and change the call of the previously modified function: {CODE(wrap="1", colors="c++")} void createFrameListener(void) { mFrameListener= new OgreBullet_Collision_testFrameListener( mSceneMgr, mWindow, mCamera, Vector3(0,-9.81,0), // gravity vector for Bullet AxisAlignedBox (Ogre::Vector3 (-10000, -10000, -10000), //aligned box for Bullet Ogre::Vector3 (10000, 10000, 10000))); mRoot->addFrameListener(mFrameListener); }{CODE} Now we have our frameListener as before but with the new parameters included. Maybe try to run it. Nothing changed yet. So, define these variables in the ''OgreBullet_Collision_testFrameListener'' class: {CODE(wrap="1", colors="c++")} class OgreBullet_CollisiontestFrameListener : public ExampleFrameListener { private: SceneManager* mSceneMgr; OgreBulletDynamics::DynamicsWorld *mWorld; // OgreBullet World OgreBulletCollisions::DebugDrawer *debugDrawer; int mNumEntitiesInstanced; std::deque<OgreBulletDynamics::RigidBody *> mBodies; std::deque<OgreBulletCollisions::CollisionShape *> mShapes;{CODE} ''mWorld'' will be the main variable for OgreBullet (like mRoot for Ogre). ''debugDrawer'' will be explained soon. ''mBodies'' and ''mShapes'' will handle the Bullet shapes and bodies. We need them to be able to free the memory and therefore get rid of memory leaks. Let's set up the basics of OgreBullet. Go to ''OgreBullet_Collision_testFrameListener'' constructor and paste this: {CODE(wrap="1", colors="c++")} mMoveSpeed = 50; // defined in ExampleFrameListener mNumEntitiesInstanced = 0; // how many shapes are created mSceneMgr = sceneMgr; // Start Bullet mWorld = new OgreBulletDynamics::DynamicsWorld(mSceneMgr, bounds, gravityVector); // add Debug info display tool debugDrawer = new OgreBulletCollisions::DebugDrawer(); debugDrawer->setDrawWireframe(true); // we want to see the Bullet containers mWorld->setDebugDrawer(debugDrawer); mWorld->setShowDebugShapes(true); // enable it if you want to see the Bullet containers SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode("debugDrawer", Ogre::Vector3::ZERO); node->attachObject(static_cast <SimpleRenderable *> (debugDrawer));{CODE} ''mMoveSpeed'' is declared in ''ExampleFrameListener.h'' and is responsible for the maximum speed of the camera movement. ''mNumEntitiesInstanced'' is a counter that we use when we create objects dynamically (we can't have two object using the same name). ''mSceneMgr'' is the Ogre Scene Manager. ''mWorld'' is the OgreBullet main variable. ''debugDrawer'' will be used to show graphical debug information about OgreBullet. We use the ''setDrawWireframe(true)'' function to set the bounding box/sphere/etc. that Bullet uses to make collisions visible; turn it off if you don't want to see it, but it's very good for debugging. Note that ''debugDrawer'' needs Ogre to be able to draw to the screen. That's why we create a node for it. Of course we need to delete the variables/deques in the destructor: {CODE(wrap="1", colors="c++")} ~OgreBullet_Collision_testFrameListener(){ // OgreBullet physic delete - RigidBodies std::deque<OgreBulletDynamics::RigidBody *>::iterator itBody = mBodies.begin(); while (mBodies.end() != itBody) { delete *itBody; ++itBody; } // OgreBullet physic delete - Shapes std::deque<OgreBulletCollisions::CollisionShape *>::iterator itShape = mShapes.begin(); while (mShapes.end() != itShape) { delete *itShape; ++itShape; } mBodies.clear(); mShapes.clear(); delete mWorld->getDebugDrawer(); mWorld->setDebugDrawer(0); delete mWorld; }{CODE} Set the position of the camera. Find ''createCamera(void)'' and change the ''setPosition'' to this: {CODE(wrap="1", colors="c++")} mCamera->setPosition(Vector3(0,18,70));{CODE} Let's create the scene. Go to ''OgreBullet_Collision_testApp'' class and find the ''createScene(void)'' function. Delete the rows which defines the default OgreHead (these were the first three row in my code). We won't create the scene here because this function is called before the ''frameListener''. I don't want to change the ''ExampleApplication.h'' file so let's go back to ''OgreBullet_Collision_testFrameListener'' constructor and insert this code after the last row. First, create the floor: {CODE(wrap="1", colors="c++")} // Define a floor plane mesh Entity *ent; Plane p; p.normal = Vector3(0,1,0); p.d = 0; MeshManager::getSingleton().createPlane( "FloorPlane", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, p, 200000, 200000, 20, 20, true, 1, 9000, 9000, Vector3::UNIT_Z); // Create an entity (the floor) ent = mSceneMgr->createEntity("floor", "FloorPlane"); ent->setMaterialName("Examples/BumpyMetal"); mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);{CODE} If you run the program now, you can see an endless (at least it seems endless) plane with texture. Let's add collision detection to it! {CODE(wrap="1", colors="c++")} OgreBulletCollisions::CollisionShape *Shape; Shape = new OgreBulletCollisions::StaticPlaneCollisionShape(Ogre::Vector3(0,1,0), 0); // (normal vector, distance) OgreBulletDynamics::RigidBody *defaultPlaneBody = new OgreBulletDynamics::RigidBody( "BasePlane", mWorld); defaultPlaneBody->setStaticShape(Shape, 0.1, 0.8); // (shape, restitution, friction) // push the created objects to the deques mShapes.push_back(Shape); mBodies.push_back(defaultPlaneBody);{CODE} Try to run it and you can see there are some errors. We need a header to be included: {CODE(wrap="1", colors="c++")} #include "Shapes/OgreBulletCollisionsStaticPlaneShape.h" // for static planes{CODE} Now the plane is detecting collisions! But how to test it when the camera is going through it? Let's create some boxes and throw them into the scene! This header is needed to be able to create a box...: {CODE(wrap="1", colors="c++")} #include "Shapes/OgreBulletCollisionsBoxShape.h" // for Boxes{CODE} ...and we need boxes. Let's redefine the'' processUnbufferedKeyInput()'' function. Originally it is defined in the ''ExampleFrameListener''. I won't start to explain it, so if you didn't already know this start reading the Ogre basic tutorials :) {CODE(wrap="1", colors="c++")} bool processUnbufferedKeyInput(const FrameEvent& evt) { bool ret = ExampleFrameListener::processUnbufferedKeyInput(evt); // create and throw a box if 'B' is pressed if(mKeyboard->isKeyDown(OIS::KC_B) && mTimeUntilNextToggle <=0) { Vector3 size = Vector3::ZERO; // size of the box // starting position of the box Vector3 position = (mCamera->getDerivedPosition() + mCamera->getDerivedDirection().normalisedCopy() * 10); // create an ordinary, Ogre mesh with texture Entity *entity = mSceneMgr->createEntity( "Box" + StringConverter::toString(mNumEntitiesInstanced), "cube.mesh"); entity->setCastShadows(true); // we need the bounding box of the box to be able to set the size of the Bullet-box AxisAlignedBox boundingB = entity->getBoundingBox(); size = boundingB.getSize(); size /= 2.0f; // only the half needed size *= 0.96f; // Bullet margin is a bit bigger so we need a smaller size // (Bullet 2.76 Physics SDK Manual page 18) entity->setMaterialName("Examples/BumpyMetal"); SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); node->attachObject(entity); node->scale(0.05f, 0.05f, 0.05f); // the cube is too big for us size *= 0.05f; // don't forget to scale down the Bullet-box too // after that create the Bullet shape with the calculated size OgreBulletCollisions::BoxCollisionShape *sceneBoxShape = new OgreBulletCollisions::BoxCollisionShape(size); // and the Bullet rigid body OgreBulletDynamics::RigidBody *defaultBody = new OgreBulletDynamics::RigidBody( "defaultBoxRigid" + StringConverter::toString(mNumEntitiesInstanced), mWorld); defaultBody->setShape( node, sceneBoxShape, 0.6f, // dynamic body restitution 0.6f, // dynamic body friction 1.0f, // dynamic bodymass position, // starting position of the box Quaternion(0,0,0,1));// orientation of the box mNumEntitiesInstanced++; defaultBody->setLinearVelocity( mCamera->getDerivedDirection().normalisedCopy() * 7.0f ); // shooting speed // push the created objects to the deques mShapes.push_back(sceneBoxShape); mBodies.push_back(defaultBody); mTimeUntilNextToggle = 0.5; } return ret; }{CODE} The code is well commented here, so I won't explain everything in detail. If you press the 'B' key, a box will be created. The box is created in several phases, like the plane before. First, we create the Ogre-box by loading a mesh. This is needed to be able to see the actual box with texture. After this, we create the shape for Bullet, which is a ''BoxCollisionShape'' this time. This means that we want a box-shaped collision object. Once this is done, we've arrived at the last step. We need a ''RigidBody'' and we use the ''setShape()'' function to bind together the box, the shape, and the ''RigidBody''. The size variable is self-explanatory, but it's worth noting that ''getBoundingBox()'' will give us the smallest box that can be drawn around the object (in our case the cube). When you run this demo and push the 'B' key, you can see the created box floating in the air. That's not what we want. So, the last step is to make the box move. We need to override the ''frameStarted()'' and ''frameEnded()'' functions. Here they are: {CODE(wrap="1", colors="c++")} bool frameStarted(const FrameEvent& evt) { bool ret = ExampleFrameListener::frameStarted(evt); mWorld->stepSimulation(evt.timeSinceLastFrame); // update Bullet Physics animation return ret; } bool frameEnded(const FrameEvent& evt) { bool ret = ExampleFrameListener::frameEnded(evt); mWorld->stepSimulation(evt.timeSinceLastFrame); // update Bullet Physics animation return ret; }{CODE} The only needed function to make Bullet functional is the ''stepSimulation()''. That's it. You can throw boxes! I hope this tutorial was helpful. If it was or if you found grammatical/coding error don't be afraid to correct them! Thanks for reading and have a nice day! :) ((Ogre Bullet Tutorial 1 - Source Code))
Search by Tags
Search Wiki by Freetags
Latest Changes
IDE Eclipse
FMOD SoundManager
HDRlib
Building Ogre V2 with CMake
Ogre 2.1 FAQ
Minimal Ogre Collision
Artifex Terra
OpenMB
Advanced Mogre Framework
MogreSocks
...more
Search
Find
Advanced
Search Help
Online Users
93 online users