In this lab we will scratch the surface of using the Bullet physics blibrary with Ogre.
Discussion thread for this lab is on Piazza
And now for the Ogre project.
Please Note:
<Bullet Root>\bin;
to Linker→General→Additional Library Directories
(Debug and Release) <Bullet Root>\src;
to C++→General→Additional Include Directories
(Debug and Release) BulletCollision_vs2010_debug.lib;BulletDynamics_vs2010_debug.lib;LinearMath_vs2010_debug.lib
to the Linker→Input→Additional Dependencies
(Debug)BulletCollision_vs2010.lib;BulletDynamics_vs2010.lib;LinearMath_vs2010.lib
to the Linker→Input→Additional Dependencies
(Release)// Header! #ifndef PHYSICS_H #define PHYSICS_H #include "btBulletCollisionCommon.h" #include "btBulletDynamicsCommon.h" #include "OgreMotionState.h" #include <vector> #include <map> class Physics{ btDefaultCollisionConfiguration* collisionConfiguration; btCollisionDispatcher* dispatcher; btBroadphaseInterface* overlappingPairCache; btSequentialImpulseConstraintSolver* solver; btDiscreteDynamicsWorld* dynamicsWorld; std::vector<btCollisionShape *> collisionShapes; std::map<std::string, btRigidBody *> physicsAccessors; public: Physics(); void initObjects(); virtual ~Physics(); btDiscreteDynamicsWorld* getDynamicsWorld(); }; #endif //PHYSICS_H // Implementation! #include "Physics.h" Physics::Physics() { } Physics::~Physics() { delete dynamicsWorld; delete solver; delete overlappingPairCache; delete dispatcher; delete collisionConfiguration; } void Physics::initObjects() { collisionConfiguration = new btDefaultCollisionConfiguration(); dispatcher = new btCollisionDispatcher(collisionConfiguration); overlappingPairCache = new btDbvtBroadphase(); solver = new btSequentialImpulseConstraintSolver(); dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration); } btDiscreteDynamicsWorld* Physics::getDynamicsWorld() { return dynamicsWorld; }
_physicsEngine = new Physics(); _physicsEngine->initObjects();
_SinbadNode→getBoundingBox().getSize()
, this function will return the bounding box the the sceneNode, which is an axis aligned box that encompasses the entities of the SceneNode and is defined by the vertex extremas + an additional 2% scale. _SinbadNode→scale(Ogre::Vector3(0.2f,0.2f,0.2f));
btRigidBody* AddDynamicCubeRigidBoidy(Ogre::SceneNode* node, Ogre::Entity* ent, btScalar mass) btRigidBody* Physics::AddDynamicCubeRigidBoidy(Ogre::SceneNode* node, Ogre::Entity* ent, btScalar mass) { Ogre::Vector3 aabbSize = ent->getBoundingBox().getSize() / 1.02f; btScalar x = 0.5f * node->getScale().x * aabbSize.x; btScalar y = 0.5f * node->getScale().y * aabbSize.y; btScalar z = 0.5f * node->getScale().z * aabbSize.z; btCollisionShape* colShape = new btBoxShape(btVector3(x, y, z)); /// Create Dynamic Objects btTransform startTransform; startTransform.setIdentity(); //rigidbody is dynamic if and only if mass is non zero, otherwise static bool isDynamic = (mass != 0.f); btVector3 localInertia(0, 0, 0); if (isDynamic) colShape->calculateLocalInertia(mass, localInertia); startTransform.setOrigin(btVector3(node->getPosition().x, node->getPosition().y, node->getPosition().z)); btQuaternion initRotation(node->getOrientation().x, node->getOrientation().y, node->getOrientation().z, node->getOrientation().w); startTransform.setRotation(initRotation); OgreMotionState* motionState = new OgreMotionState(startTransform, node); btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, motionState, colShape, localInertia); btRigidBody* body = new btRigidBody(rbInfo); dynamicsWorld->addRigidBody(body); return body; }
#ifndef OGREMOTIONSTATE_H #define OGREMOTIONSTATE_H #include "LinearMath\btMotionState.h" #include "OGRE\Ogre.h" class OgreMotionState : public btMotionState { public: OgreMotionState(const btTransform &initialpos, Ogre::SceneNode *node) { mVisibleobj = node; mPos1 = initialpos; } virtual ~OgreMotionState() { } void setNode(Ogre::SceneNode *node) { mVisibleobj = node; } virtual void getWorldTransform(btTransform &worldTrans) const { worldTrans = mPos1; } virtual void setWorldTransform(const btTransform &worldTrans) { if (NULL == mVisibleobj) return; btQuaternion rot = worldTrans.getRotation(); mVisibleobj->setOrientation(rot.w(), rot.x(), rot.y(), rot.z()); btVector3 pos = worldTrans.getOrigin(); mVisibleobj->setPosition(pos.x(), pos.y(), pos.z()); } protected: Ogre::SceneNode *mVisibleobj; btTransform mPos1; }; #endif //OGREMOTIONSTATE_H
// Create the plane. Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0); Ogre::MeshManager::getSingleton().createPlane("plane", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 1500, 1500, 200, 200, true, 1, 5, 5, Ogre::Vector3::UNIT_Z); // Set the plane as the ground and add a texture to it. Ogre::Entity* ground = _sceneManager->createEntity("LightPlaneEntity", "plane"); Ogre::SceneNode* groundNode = _sceneManager->getRootSceneNode()->createChildSceneNode(); groundNode->attachObject(ground); ground->setMaterialName("Examples/BeachStones"); groundNode->setPosition(0, -1, 0); // Create the collision shape, and give it the ground plane normals. btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(plane.normal.x, plane.normal.y, plane.normal.z), 0); // Create the collision transform. btTransform groundTransform; // Set up the collision location and orientation. groundTransform.setIdentity(); groundTransform.setOrigin(btVector3(groundNode->getPosition().x, groundNode->getPosition().y, groundNode->getPosition().z)); btQuaternion initRotation(groundNode->getOrientation().x, groundNode->getOrientation().y, groundNode->getOrientation().z, groundNode->getOrientation().w); groundTransform.setRotation(initRotation); // Give the plane a mass of 0, because our plane will be static, thus will not moce. btScalar mass(0.0f); // Set the ground as a static object. bool isDynamic = false; // This plane isnt going to be moving so i dont care about setting the motion state btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform); btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, groundShape); btRigidBody* body = new btRigidBody(rbInfo); //add the body to the dynamics world _physicsEngine->getDynamicsWorld()->addRigidBody(body);
int ringCount = 16; int ringheight = 10; for (int i = 0; i < ringheight; ++i) { for (int j = 0; j < ringCount; ++j) { Ogre::Entity* cubeEnt = _sceneManager->createEntity("Cube.mesh"); Ogre::SceneNode* cubeNode = _sceneManager->getRootSceneNode()->createChildSceneNode(); cubeNode->setScale(0.006f, 0.004f, 0.006f); Ogre::Radian angle((Ogre::Math::TWO_PI / ringCount)*j + (Ogre::Math::TWO_PI / ringCount)*0.5f*(i%2) ); cubeNode->setOrientation(Ogre::Quaternion(-angle, Ogre::Vector3::UNIT_Y)); //cubeNode->setPosition(j*0.62+((i%2)*0.31f), i*0.405-(1-0.2), 0); cubeNode->setPosition(Ogre::Math::Cos(angle) * 1.9f, i*0.405f - (1 - 0.2f), Ogre::Math::Sin(angle) * 1.9f); cubeNode->attachObject(cubeEnt); btRigidBody* temp = _physicsEngine->AddDynamicCubeRigidBoidy(cubeNode, cubeEnt, 1); temp->setFriction(1); } }
// HEADER! #pragma once #include <Ogre.h> #include <OgreApplicationContext.h> // A simple indepdendent camera that can be flown around the scene // using the mouse and WASD keys, while pressing and holding the // right mouse button. class RoamingCamera { public: // Constructor // sceneManager: contains the scene the camera will roam about // win: is a valid render window into which the camera view will get rendered RoamingCamera(Ogre::SceneManager* sceneManager, Ogre::RenderWindow* win, Physics* physicsEngine); // Destructor ~RoamingCamera(); // Update // dt: Elapsed time in seconds from the last time this method got called // state: Valid SDL keyboard state, as retrieved with SDL_GetKeyboardState(..) void update(Ogre::Real dt, const Uint8 * state); private: Ogre::Camera* _cam; // My actual camera Ogre::SceneNode* _node; // My scene graph node Physics* _physicsEngine; }; // Implementation! #include "RoamingCamera.h" RoamingCamera::RoamingCamera(Ogre::SceneManager* sceneManager, Ogre::RenderWindow* win, Physics* physicsEngine) { _physicsEngine = physicsEngine; // Attaching the camera _node = sceneManager->getRootSceneNode()->createChildSceneNode(); _cam = sceneManager->createCamera("myCam"); _node->attachObject(_cam); _node->setPosition(0, 0, 50); _node->lookAt(Ogre::Vector3(0, 0, 0), Ogre::Node::TransformSpace::TS_WORLD); // Configuring the camera _cam->setNearClipDistance(5); Ogre::Viewport* vp = win->addViewport(_cam); vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0)); _cam->setAspectRatio(Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight())); } RoamingCamera::~RoamingCamera() { } void RoamingCamera::update(Ogre::Real dt, const Uint8 * state) { int x = 0, y = 0; // Leave if right mouse button is not being pressed // ...but also retrieve and store mouse movement if (!(SDL_GetRelativeMouseState(&x, &y) & SDL_BUTTON_RMASK)) return; // Construct displacement vector Ogre::Vector3 vec = Ogre::Vector3(0, 0, 0); if (state[SDL_SCANCODE_W]) { vec = Ogre::Vector3(0, 0, -1); } if (state[SDL_SCANCODE_S]) { vec = Ogre::Vector3(0, 0, 1); } if (state[SDL_SCANCODE_A]) { vec = Ogre::Vector3(-1, 0, 0); } if (state[SDL_SCANCODE_D]) { vec = Ogre::Vector3(1, 0, 0); } if (state[SDL_SCANCODE_Q]) { vec = Ogre::Vector3(0, 1, 0); } if (state[SDL_SCANCODE_E]) { vec = Ogre::Vector3(0, -1, 0); } // Construct view rotation float rotX = x * dt * -1 * 2.0f; float rotY = y * dt * -1 * 2.0f; // Update camera with new displacement and rotation _cam->yaw(Ogre::Radian(rotX)); _cam->pitch(Ogre::Radian(rotY)); _cam->moveRelative(dt * 4.0 * vec); }
make it shoot boxes when some button is pressed, you can shoot boxes like this:
// Create a cube entity. Ogre::Entity* cubeEnt = _sceneManager->createEntity("Cube.mesh"); Ogre::SceneNode* cubeNode = _sceneManager->getRootSceneNode()->createChildSceneNode(); cubeNode->setScale(0.005f, 0.005f, 0.005f); // Set the position of the cube to the front of the origin of the camera cubeNode->setPosition(_cam->getPosition() + _cam->getDirection()); cubeNode->attachObject(cubeEnt); // Now make the cube a rigid body, give it some linearVelocity and add it to the physics world btRigidBody* boxBody = _physicsEngine->AddDynamicCubeRigidBoidy(cubeNode, cubeEnt, 2); boxBody->setLinearVelocity(btVector3(_cam->getDirection().x, _cam->getDirection().y, _cam->getDirection().z) * 30);
// Now update the physics world with the delta time. "Note: normally we would want to have the physics world update a little more independant of the framerate, but this will do for now :)" _physicsEngine->getDynamicsWorld()->stepSimulation(evt.timeSinceLastFrame);
Attention!
<YourOgreSDK>\bin\Release\plugins.cfg
Check out these pre-processor variables to help you out#if _DEBUG cf.load("../LabFiles/OgreConfig/resources_d.cfg"); #elif NDEBUG cf.load("../LabFiles/OgreConfig/resources.cfg"); #endif #if _DEBUG _root = new Ogre::Root("../LabFiles/OgreConfig/plugins_d.cfg","../LabFiles/OgreConfig/ogre.cfg", "../LabFiles/ogre.log"); #elif NDEBUG _root = new Ogre::Root("../LabFiles/OgreConfig/plugins.cfg","../LabFiles/OgreConfig/ogre.cfg", "../LabFiles/ogre.log"); #endif
Upload your commented source files into Lab9 in MySchool (zip them up if more than one).