1

I am using Bullet Physics and the gravity in my world seems to be too weak.

This means that items fall too slowly and general values don't make as much sense as they should.

While I know that "values" used in bullet are arbitrary, but the general usages suggests that 1 unit == 1 meter.

So gravity would be -9.80665f and one meter cube would be 1.0f,1.0f,1.0f

But when I set my world up in this way it takes about 18 seconds for my box to fall 100 units.

This is much much slower then I would expect.

So am I setting up the world incorrectly?

My world

CollisionConfiguration = new btDefaultCollisionConfiguration();
Dispatcher = new btCollisionDispatcher(CollisionConfiguration);        
Broadphase = new btDbvtBroadphase();                                         
Solver = new btSequentialImpulseConstraintSolver();                      
DynamicsWorld = new btDiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConfiguration);
DynamicsWorld->setGravity(btVector3(0.0f, -9.80665f, 0.0f));

PhysicsClock.reset();

Stepping the world (this gets called 32 times a second)

Microseconds = PhysicsClock.getTimeMicroseconds();
PhysicsClock.reset();
DynamicsWorld->stepSimulation(Microseconds / 1000000.0f);

My body

btCapsuleShape Shape(0.25f, 1.75f);
Body = new btRigidBody(80, &MotionState, &Shape); 

Removed    Body.setDamping(0.6f, .9999f);
Removed    Body.setAngularFactor(btVector3(0, 0, 0));
Removed    Body.setActivationState(DISABLE_DEACTIVATION);

Adding to the world

DynamicsWorld.addRigidBody(Body);

Motion state

void getWorldTransform(btTransform& centerOfMassWorldTrans) const override
{
    centerOfMassWorldTrans = m_Transform;
}


void setWorldTransform(const btTransform& centerOfMassWorldTrans) override
{
   m_Transform = centerOfMassWorldTrans;
   ...

Code used to control the stepping of the world

void WorldServer::UpdateWorldThread(void)
{
   LARGE_INTEGER    l_Frequency;
   float            l_TickInterval;

   float            l_Scale;
   float            l_Delay;

   int              l_TickBase;
   LARGE_INTEGER    l_TimeBase;

   LARGE_INTEGER    l_Now;

   QueryPerformanceFrequency(&l_Frequency);                                     //How many ticks per second
   l_TickInterval = l_Frequency.QuadPart / c_WorldUpdateFrequency;  //How many ticks per interval

   l_Scale = l_Frequency.QuadPart / 1000.0f;                                        //Scale for milliseconds

                                                                        //Create a base that will allow us to catch frames up
   QueryPerformanceCounter(&l_TimeBase);        //Store base time
   l_TickBase = 1;                                  //Store base tick

   while (IsRunning())      //While the world is running
   {
************This bit is what calls the method to step the world

      UpdateAll();              //Update
                                  //Number of milliseconds to wait
      QueryPerformanceCounter(&l_Now);
      l_Delay = ((l_TimeBase.QuadPart - l_Now.QuadPart) + (l_TickBase * l_TickInterval)) / l_Scale;

      //If there has been a large delay then we need to reset the base
      if (l_Delay < -c_WorldUpdateDelayTolerance)
      {
         QueryPerformanceCounter(&l_TimeBase);      //Store base time
         l_TickBase = 0;                                    //Store base tick

         LogWarning("World has dropped %.2f ticks.", l_Delay / -l_TickInterval);
      }

      Sleep(max(0.0f, l_Delay));                            //Yield CPU (this allows the thread to execute at a constant frequency)

      l_TickBase++;                                     //Count tick from base
   }

   //LogMessage("World UpdateWorldThread exited.");
}

I do have a number of other setting, but when I remove them I still have the same problems.

So what am I missing!

Note I know I could scale the world and simply multiple particular values by a common scale. But should i need to do this when my objects are in the "expected" scale?

I can definitely post more code if needed. Just ask.

I have done some more testing and I can now say that it takes 19.374506 seconds to fall 100 units.

I know this by using the following code

   l_Microseconds = m_PhysicsClock.getTimeMicroseconds();
   m_PhysicsClock.reset();
   m_DynamicsWorld->stepSimulation(l_Microseconds / 1000000.0f);

   total += l_Microseconds;

When the cube hits the ground I took a look at total and it was 19374506.

Paul Spain
  • 191
  • 13

2 Answers2

3

Let's do a bit of math to see if this is correct or not. Your box starts at ŷ = 100m, lets assume it has to travel exactly -100m to reach 0m. Then we can get a result if we insert this into the equation y(t) = (1/2)·gt² + ŷ: 0 = (1/2)·(-9.80665)t² + 100, solving for t yields to around 4.5s, so there must be something wrong with your configuration, as it takes much longer for you.

But as your code seems to look ok, I can't think of many pitfalls. Are you sure about your 18 seconds? Do you have a somewhat constant framerate? Compare your code with the hello world example from BulletPhysics, maybe you find a minor flaw with big influence. Try reducing the mass, as it can have an impact on the stability of the engine, as pointed out by Jon in the comments.


Some offtopic-last-tip: It's better to keep physics at a constant simulation time such that it doesn't do more when your game goes laggy. This can be archived by summing the seconds up and subtract until the sum is lower than a certain threshold. Here is an example in pseudo code for you:

time += elapsedTime;
while(time >= physicsSimulationTimeStep) //mostly (1/60)s, but you decide
{
    time -= physicsSimulationTimeStep;
    physics.step(physicsSimulationTimeStep);
}
NaCl
  • 131
  • 1
  • 3
  • Thanks for the math part that goes some way to prove i have a problem. – Paul Spain Apr 21 '16 at 17:21
  • I already have a control method for calling the world at a "constant rate" as per my question i step the world 32 times a second. I have added the code that i use to control this to my question. – Paul Spain Apr 21 '16 at 17:22
  • I have done some more timing (my question has been updated) but yes its taking around 18 seconds to fall 100 units – Paul Spain Apr 21 '16 at 17:48
  • And I already have code for making sure the games runs at a smooth step rate. I will go through all the code again and see if i have misses anything. – Paul Spain Apr 21 '16 at 19:00
  • It's really difficult to see anything, as it looks ok. I know it can be a hassle, but using some kind of testing system could prevent this from happening in first place – NaCl Apr 21 '16 at 19:10
  • I did notice the problem ages ago, but i scaled things just to get going. Its only now the game is a bit more developed that I really want to work out whats wrong. For now it looks like I will have to chop things up some more and try and find out where i have done wrong. – Paul Spain Apr 21 '16 at 19:44
2

After taking a much much much closer look at my code I have managed to find the bug!

I had two problems.

Problem 1, And I can't believe I missed this. In the base class of my object there was a rogue bit of code

Body.setDamping(0.6f, .9999f);

I missed this as it was in the base, not the subclass that I use. It must have been put in there for a reason a long time back.

But that did not solve the problem. Even when I took the dampening out it was still taking around 8 seconds to fall 100 units.

So after yet more code searching it clicked!

Problem 2

I call stepworld 32 times a second. The code for this is in the question. The problem with this is that DynamicsWorld->stepSimulation assumes a 60Hz rate by default. So it ends up running approximately 50% slower then it should, And that is why i got an ~8 second fall time when it should be ~4.

To fix this I changed the line to

m_DynamicsWorld->stepSimulation(l_Microseconds / 1000000.0f, 1.0f, 1.0f / c_WorldUpdateFrequency);

where c_WorldUpdateFrequency = 32 (this will match the controlling thread)

And bingo! my objects now fall at the correct speed and all is good in the world!

So in summary, the 3rd parameter of stepSimulation should match how frequently its being called.

Thanks for the help.

Paul Spain
  • 191
  • 13