1
\$\begingroup\$

I'm adding bullet physics to my engine. The physics simulation bits are all working nicely, but one bit I'm struggling with is being able to move objects using their co-ordinates, and then have them affect other bullet objects. I currently have this code just before I step the simulation, and this moves all of the objects to the co-ordinates that the game engine thinks the object should be, due to outside movement.

btTransform trans;
trans.setFromOpenGLMatrix(glm::value_ptr(host->getTransMat() * host->getRotMat()));

motionState->setWorldTransform(trans);
body->setWorldTransform(trans);

Then I step the simulation, and move every object to where bullet thinks it should be. I am aware there are nicer ways to do this part (custom written motionstate classes I think) but I want to get the logic down first. This works, but moving a cube directly into another causes the second cube to just shake a bit.

I've read in few places I should be applying forces to objects, but:

  1. I don't really want to expose the btRigidBody and physics stuff to the core gameobject, and

  2. I have a lot of code that does it's own movements using co-ordinates, and I don't really want to rewrite it, although I will if it's the only way.

Could I replace the code below with something that compares the position of the gameobject to the rigidbody's position, and applies the correct force to make that happen? How would I implement this code? It can't be as simple as F = MA can it, given that this would happen any frame?

Edit 1:

I have implemented the formula provided by DMGregory and I've not had any success. I've tried swapping this out for applyCentralImpulse too. The objects just stay stationary and anything falling just goes into hyper speed. This runs for every physics object just before step sim, and then the simulations positions are applied to back to their hosts.

    if (host == nullptr)return;

btVector3 newPos = convert(host->getPos());

btVector3 oldPos = body->getWorldTransform().getOrigin();

btVector3 dist = newPos -oldPos;


btVector3 acc = 2 * ((newPos - oldPos -( body->getLinearVelocity() * timeStep)) / (pow(timeStep, 2)));

if (dist.length() > btScalar(0.1f))
{
    std::cout << acc.length() << "large acc \n";
}

body->applyCentralForce(mass * acc);
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

My usual approach here — and one I've seen work well in VR and motion controlled games too — is to compute a velocity that will bring the previous position of the object's physics body to the desired target position in one physics step.

$$\vec v_{desired} = \frac {\vec p_{desired} - \vec p_{previous}} {\Delta t}$$

Here \$ \Delta t\$ is the duration of your physics timestep, not necessarily your frame time if those are decoupled in your case.

Some APIs will let you set the velocity directly, overriding other physics effects on it. If you can only apply forces though, then we need to apply an acceleration to achieve this. Working from the equation for movement in constant acceleration...

$$\vec p (t) = \vec p (0) + \vec v \cdot t + \vec a \cdot \frac {t^2} 2\\ \vec a_{net} = 2 \cdot \frac {\vec p_{desired} - \vec p_{previous} - \vec v_{previous} \cdot \Delta t} {\Delta t^2}$$

This is the net acceleration required to land at the desired point. If you have other continuous forces acting on this body (like gravity), subtract them to get the intervention acceleration that you need to apply.

Then to convert this acceleration to a force to apply, it really is just \$\vec F = m \cdot \vec a\$ ;)

You can use a similar strategy to set the angular velocity or apply an angular acceleration in order to bring an orientation into sync. First you compute the difference in orientation between the two:

$$R_{difference} = R_{desired} \cdot {R_{previous}}^{-1}$$

Then convert this to an angle-axis representation, and scale the axis vector by the angle in radians over delta time. That gives you your angular velocity to set.

\$\endgroup\$
2
  • \$\begingroup\$ Yes and no. Nothing was happening as the mass was 0. But then with that formula it just gets sent instantly to infinite co-ords. I found by dividing the acc by a fudge value I get working results, but I've found other issues too that I'm not sure are related. The fudge value I've used is 100 for now, results in fairly convincing replication of the original movement \$\endgroup\$
    – Figwig
    Commented Apr 1, 2019 at 21:35
  • \$\begingroup\$ For example, when colliding with other objects, the other objects aren't affected until the centre of the box passes into another collider, but normal collisions that which this code doesn't affect, are fine \$\endgroup\$
    – Figwig
    Commented Apr 1, 2019 at 21:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .