]> git.uio.no Git - private-olgabo.git/commitdiff
sc
authorolgabo <olgabo@ifi.uio.no>
Wed, 14 Nov 2012 12:39:27 +0000 (13:39 +0100)
committerolgabo <olgabo@ifi.uio.no>
Wed, 14 Nov 2012 12:39:27 +0000 (13:39 +0100)
msreport/concl.tex
msreport/design.tex
projects/ogrebullet/Game.cpp

index 150af21c6f76c9dbccf3874c2f8f21625c0304e1..2136b9001d539056334a79ff0cd6f9b420571b80 100644 (file)
@@ -1,5 +1,7 @@
 \chapter{Conclusion}\label{chap:concl}
 
+After having made a few honest attemps to achieve the desired funtionality by integrating Bullet into our projects, we concluded that Bullet itself was a rather useful framework. It is well documented and has an API available online. Nevertheless, most of the wrappers seem to be unofficial \/"hobby" projects and do not provide clear documentation, which introduces a number of complications in using them. A simple broadfase collision detection would be a possible solution. However, using Bullet for only simple collision detection in our case would create much unnecessary overhead. \
+
 %Here are some ideas for the conclusion.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
index 2aec940e108ea6807179179c88b307178204fba0..c2c25feb264041276c57e31a057cb75ca30920ac 100644 (file)
@@ -309,6 +309,10 @@ OgreBulletDynamics::DynamicsWorld *mWorld;  // Bullet dynamics world wrapped by
 mWorld = new OgreBulletDynamics::DynamicsWorld(mSceneMgr,  Ogre::AxisAlignedBox 
        (Ogre::Vector3 (-10000, -10000, -10000),Ogre::Vector3 (10000,  10000,  10000)), gravityVector);
 \end{lstlisting}
+The physics animation needs to be update every time a new frame is rendered:
+\begin{lstlisting}
+mWorld->stepSimulation(evt.timeSinceLastFrame); 
+\end{lstlisting}
 
 Each time we create an object that we want to assign some physical properties to, we need to create a rigid body object and assign some collision shape to it. That is useful for non-animated objects that do not change their shape over time. Consider a very simple example: we would like our avatar to be able to throw balls and implement it as follows:
 
@@ -368,10 +372,10 @@ mBodies.push_back(defaultBody);
 \centering
 \epsfig{file=avatar-ball.eps,width=9cm}
 \caption{Using Bullet with OgreBullet for collision detection: collision shapes} 
-\label{fig:avatar-call}
+\label{fig:avatar-ball}
 \end{figure} 
 
-As a result, out avatar can throw balls that behave correctly in the physical world (Figure ...). We set a Bullet container around the avatar in a similar way we did for the box, which makes it possible for the avatar to interact with the physical objects, which are balls in this example. If the avatar collides with the ball, the ball will get a physical impulse an move in the corresponding direction. If a ball will fall on the avatar, it would bounce off. However, the avatar itself would not be affected. We do not want avatar's motion to be affected by other physical objects, since it is controlled by user input. Therefore, we set the avatar's bullet body to be kinematic, which means it can affect other physical bodies, but not vice versa:
+As a result, out avatar can throw balls that behave correctly in the physical world (Figure~\ref{fig:avatar-ball}). We set a Bullet container around the avatar in a similar way we did for the box, which makes it possible for the avatar to interact with the physical objects, which are balls in this example. If the avatar collides with the ball, the ball will get a physical impulse an move in the corresponding direction. If a ball will fall on the avatar, it would bounce off. However, the avatar itself would not be affected. We do not want avatar's motion to be affected by other physical objects, since it is controlled by user input. Therefore, we set the avatar's bullet body to be kinematic, which means it can affect other physical bodies, but not vice versa:
 \begin{lstlisting}
 playerRididBody->setKinematicObject(true); 
 \end{lstlisting}
@@ -465,7 +469,7 @@ As a result, all bone containers were misplaced, as illustrated on Figure ~\ref{
 \label{fig:wrong-bone-containers-full}
 \end{figure} 
 
-To figure out why the solution did not produce expected results, we could approach the problem from different perspectives. One possibility would be to analyze the OgreBullet's source code more throughly and spot possible mistake we have done (for example, usage of wrong transformation matrices). Another option would be to use a different wrapper for Bullet, like \textit{BtOgre}\footnote{https://github.com/nikki93/btogre}. However, the problem could originate from Bullet itself. When using some of the collision shapes, we got the following message at runtime:
+To figure out why the solution did not produce expected results, we could approach the problem from different perspectives. One possibility would be to analyze the OgreBullet's source code more throughly and spot possible reasons for the proble. Another option would be to use a different wrapper for Bullet, like \textit{BtOgre}\footnote{https://github.com/nikki93/btogre}. However, the problem could originate from Bullet itself. When using some of the collision shapes, we got the following message at runtime:
 
 \begin{quotation}
 "Overflow in AABB, object removed from simulation. 
@@ -475,14 +479,36 @@ Please include above information, your Platform, version of OS.
 
 Thanks."
 \end{quotation}
+In any case, since creating a simple collision geometry without taking animated mesh into account produces correst results, we consider that option to be more effective. An optimal way to implement collision detection for an avatar is to use Bullet's Kinematic Character Controller\footnote{http://www.continuousphysics.com/Bullet/BulletFull/classbtKinematicCharacterController.html}. However, there is no wrapper class for it in OgreBullet. \ 
 
-An optimal way to do that is to use Bullet's Kinematic Character Controller\footnote{http://www.continuousphysics.com/Bullet/BulletFull/classbtKinematicCharacterController.html}. However, there is no wrapper class for it in OgreBullet. 
-
-After having made a few honest attemps to achieve the desired funtionality by integrating Bullet into our projects, we concluded that Bullet itself was a rather useful framework. It is well documented and has an API available online. Nevertheless, most of the wrappers seem to be unofficial \/"hobby" projects and do not provide clear documentation, which introduces a number of complications in using them. At the same time, we could try to implement a wrapper 
+A simple way to perform simple broadphase collision with Bullet is by calling Bullet's collision dispatcher directly:
 
+\begin{lstlisting}
+// get the pointer to Bullet's dynamics world object
+btDynamicsWorld *bulletWorld = mWorld->getBulletDynamicsWorld();
+int numberOfManifolds = btWorld->getDispatcher()->getNumManifolds();
+btSimpleBroadphase *simpleBroadphase = new btSimpleBroadphase();
+   
+for (int i = 0; i < numberOfManifolds; i++)
+{
+    btPersistentManifold* contactManifold =  btWorld->getDispatcher()->getManifoldByIndexInternal(i);
+   
+    int numberOfContacts = contactManifold->getNumContacts();
+      
+    for (int j = 0; j<numberOfContacts; j++)
+    {
+        btManifoldPoint& contactPoint = contactManifold->getContactPoint(j);
+        if (contactPoint.getDistance() < 0.f)
+        {
+            // collision: do something if necessary
+        }   
+    }
+}
+\end{lstlisting}
 
-Besides, using Bullet for only simple collision detection in our case would create much unnecessary overhead. \
+It is necessary to note that for determining exactly which objects collide, we need to keep track of all Bullet rigid bodies that we have create through OgreBullet objects. Although, if we only need to detect collision (for example, if we only add collision geometry for avatar objects and want to know when they collide, as shown on Figure ... ), then using the above algorithm is sufficient. \
 
+We tried this solution, and the outcome was successful. However, it required considerably more computational power and therefore reduced application's responsiveness. \
 
 \begin{figure}[hp]
 \centering
@@ -498,7 +524,7 @@ Besides, using Bullet for only simple collision detection in our case would crea
 \label{fig:collision-avatar}
 \end{figure} 
 
-To make sure that collision detection computations do not significantly affect rendering rate, we decided to use essentially simplified collision detection method instead. Every time we change the position of an object \begin{math}O\end{math} in the virtual world, we calculate the distance between its new position and every other object it can collide with. Collision occurs if the distance between \begin{math}O\end{math} and any other object exceeds a certain limit. For all the static game world objects, distance to any point in the object's bounding box is used to detect collision with a movable object (Figure~\ref{fig:collision-world}). For movable objects, such as avatars, we use positions instead of bounding box geometry, since a bounding box typically encloses the object's mesh in its original state, before it is animated. Therefore, using the distance to the objects center is easier for adjusting calculations (Figure~\ref{fig:collision-avatar}). If collision occurs, we move \begin{math}O\end{math} back to its previous position.\
+To avoid significantly decreasing the frame rendering rate by expensive collision detection computations, we decided to use essentially simplified collision detection method instead. Every time we change the position of an object \begin{math}O\end{math} in the virtual world, we calculate the distance between its new position and every other object it can collide with. Collision occurs if the distance between \begin{math}O\end{math} and any other object exceeds a certain limit. For all the static game world objects, distance to any point in the object's bounding box is used to detect collision with a movable object (Figure~\ref{fig:collision-world}). For movable objects, such as avatars, we use positions instead of bounding box geometry, since a bounding box typically encloses the object's mesh in its original state, before it is animated. Therefore, using the distance to the objects center is easier for adjusting calculations (Figure~\ref{fig:collision-avatar}). If collision occurs, we move \begin{math}O\end{math} back to its previous position.\
 
 Most physics engine also simulate gravity. In our game world, all dynamic objects can only move on a plane, along X and Z axes in OGRE's coordinate system, and never along the Y axis. Therefore, we do not need to simulate gravity and can only translate the objects to required positions, according to user input or kinematic state updates. 
 
@@ -647,7 +673,6 @@ bool Game::frameRenderingQueued(const FrameEvent &evt)
     return BaseApplication::frameRenderingQueued(evt);
 }
 \end{lstlisting}
-\
 By updating the motion states of the objects each time a new frame is queued for rendering and taking into account the time that passed since last frame was rendered in calculating new positions of the objects, we simulate motion that is smooth. While the local player entity is being controlled by user input, all the remote player entities are not. The information about their kinematic states is extracted from the state update messages, but those are received with the interval of 200 ms. If we decided to only update the positions of remote players every time an update message arrives, the motion would no longer look realistic and the user would see remote players jumping from one position to another instead of moving smoothly. Doing that should be avoided, so remote players' motion needs to be evenly interpolated between the known positions, which we can simply refer to as points. \
 
 Interpolation between points in the virtual world space can be generally done in two ways:
index e852692deb2d97c0f49f3d3c676216e698c9bcca..05ac2d28eca0c9d9fa34620ad2accf8f1d5cfab5 100644 (file)
@@ -40,6 +40,7 @@ Game::~Game(void)
 //-------------------------------------------------------------------------------------
 void Game::init()
 {
+    std::cout << "init\n";
 
     mNumEntitiesInstanced = 0; // how many shapes are created
        
@@ -255,6 +256,8 @@ void Game::createScene(void)
 
     // create local player and attach camera to it
    createPlayer(myPlayerId);
+   createPlayer(6);
+
     playerNodes[myPlayerId]->attachObject(daylight);
     playerNodes[myPlayerId]->attachObject(sunlight);
    
@@ -597,11 +600,15 @@ bool Game::processUnbufferedInput(const Ogre::FrameEvent& evt)
             transVector.z = 0;
         }    
     }    
+    bool collision = CollisionCheck();
+    
+  //  if (!collision)
+   // {
+        playerNodes[myPlayerId]->translate(transVector * evt.timeSinceLastFrame, Ogre::Node::TS_LOCAL);
+        playerNodes[myPlayerId]->yaw(Ogre::Degree(mRotate) * evt.timeSinceLastFrame);
+   // }
    
-    playerNodes[myPlayerId]->translate(transVector * evt.timeSinceLastFrame, Ogre::Node::TS_LOCAL);
-    playerNodes[myPlayerId]->yaw(Ogre::Degree(mRotate) * evt.timeSinceLastFrame);
-   //  CollisionCheck();
+    
     mRotate = 0;
     
     return true;
@@ -946,44 +953,49 @@ void Game::restoreCameraPosition()
 //-------------------------------------------------------------------------------------
 bool Game::CollisionCheck()
 {
+  
     int numManifolds = btWorld->getDispatcher()->getNumManifolds();
     btSimpleBroadphase *simplebp = new btSimpleBroadphase();
-    bool overlap = simplebp->testAabbOverlap(btRigidBodies[myPlayerId]->getBroadphaseProxy(), btRigidBodies[6]->getBroadphaseProxy()); 
-    if (overlap)
-        std::cout << "overlap\n";
+   
+  //  bool overlap = simplebp->testAabbOverlap(btRigidBodies[myPlayerId]->getBroadphaseProxy(), btRigidBodies[6]->getBroadphaseProxy()); 
+   
+    //if (overlap)
+      //  std::cout << "overlap\n";
     for (int i = 0; i < numManifolds; i++)
     {
         btPersistentManifold* contactManifold =  btWorld->getDispatcher()->getManifoldByIndexInternal(i);
-        btRigidBody* obA = static_cast<btRigidBody*>(contactManifold->getBody0());
-        btRigidBody* obB = static_cast<btRigidBody*>(contactManifold->getBody1());
-        if (obA->isKinematicObject())
-       //     std::cout << "kinematic\n";
+      //  btRigidBody* obA = static_cast<btRigidBody*>(contactManifold->getBody0());
+       // btRigidBody* obB = static_cast<btRigidBody*>(contactManifold->getBody1());
+        //if (obA->isKinematicObject())
+          //  std::cout << "kinematic\n";
 
-        if (obA == btRigidBodies[myPlayerId])
-            std::cout << "me\n";
+        //if (obA == btRigidBodies[myPlayerId])
+          //  std::cout << "me\n";
 
         int numContacts = contactManifold->getNumContacts();
-        std::cout << numContacts << " numContacts\n";
+      
         for (int j=0;j<numContacts;j++)
         {
-            btManifoldPoint& pt = contactManifold->getContactPoint(j);
-            if (pt.getDistance()<0.f)
+            btManifoldPoint& contactPoint = contactManifold->getContactPoint(j);
+            if (contactPoint.getDistance() < 0.f)
             {
-                const btVector3& ptA = pt.getPositionWorldOnA();
-                const btVector3& ptB = pt.getPositionWorldOnB();
-                const btVector3& normalOnB = pt.m_normalWorldOnB;
+             //   const btVector3& ptA = pt.getPositionWorldOnA();
+               // const btVector3& ptB = pt.getPositionWorldOnB();
+                 //   const btVector3& normalOnB = pt.m_normalWorldOnB;
                 std::cout << "collision\n";
-                std::cout << pt.getDistance() << "\n";
-                pt.setDistance(50.0f);
-               // return true;
+               // std::cout << pt.getDistance() << "\n";
+               // pt.setDistance(50.0f);
+                std::cout << "true\n";
+                return true;
 
             }   
-            else 
-                std::cout << pt.getDistance() << "\n";
+            //else 
+              //  std::cout << pt.getDistance() << "\n";
         }
 
            
     }
+    std::cout << "false\n";
     return false;
 
 }