I have gravity needs that are better served through per-object gravity (beyond the supported gravity scale), so I am attempting to implement gravity myself. The obvious thing to do is to apply a force to each b2_dynamicBody each frame. Unfortunately, bodies with higher mass looked like they were dragging through the air.
I traced it down to b2Island::Solve's velocity integration:
v += h * (b->m_gravityScale * gravity + b->m_invMass * b->m_force);
So then, gravity is not scaled by 1/mass like the rest of the forces being applied to the body. My solution is to counteract the effect of the m_invMass by prescaling the gravity force.
The loop looks like this:
b2Vec2 gravityVector( ... );
// Apply gravity equally to each rigid body.
for ( b2Body *b = world->GetBodyList(); b; b = b->GetNext() )
if ( b->GetType() != b2_dynamicBody )
float32 invMass = 1 / b->GetMass();
b2Vec2 g( gravityVector.x / invMass, gravityVector.y / invMass );
b->ApplyForceToCenter( g );
Another problem is that calling ApplyForceToCenter() calls SetAwake(). This means no dynamic bodies are ever resting. I am going to look into coding a workaround to this.
Any suggestion on how to avoid all of this useless computation just to take control over the gravity processing is welcome.