Manually positioning dynamic rigid bodies with setWorldTr...

a8sdyf98as
Posts: 2
Joined: Sat Nov 14, 2009 3:52 pm

Manually positioning dynamic rigid bodies with setWorldTr...

Post by a8sdyf98as »

I'm trying to manually place a dynamic rigid body using setWorldTransform, but I'm running into some snags. I'm setting a new transform between simulation steps, but my "changes" seem to be overwritten/ignored on subsequent steps.

Here's a program demonstrating my problem (output follows):

Code: Select all

#include <iostream>

#include "btBulletDynamicsCommon.h"

struct MyMotionState : public btMotionState
{
    MyMotionState(const btTransform& transform)
        : mTransform(transform)
    {
    }

    virtual void getWorldTransform(btTransform& returnTransform) const
    {
        std::cout << "getWorldTransform called... Y: " << mTransform.getOrigin().getY() << std::endl;
        returnTransform = mTransform;
    }

    virtual void setWorldTransform(const btTransform& newTransform)
    {
        std::cout << "setWorldTransform called... Y: " << newTransform.getOrigin().getY() << std::endl;

        mTransform = newTransform;
    }

    btTransform mTransform;
};

const float DEFAULT_X = 0.0f;
const float DEFAULT_Y = 10.0f;
const float DEFAULT_Z = 0.0f;

const float RADIUS = 5.0f;
const float MASS   = 5.0f;

const float SIM_DELAY = 10.0f;
const int SLEEP_DELAY = 1000; // ms

int main()
{
    btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
    btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);

    btBroadphaseInterface* broadphase = new btDbvtBroadphase;
    btConstraintSolver* solver = new btSequentialImpulseConstraintSolver;
    btDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);


    btTransform startTransform;
    startTransform.setIdentity();
    startTransform.setOrigin(btVector3(DEFAULT_X, DEFAULT_Y, DEFAULT_Z));
    btCollisionShape* fallShape = new btSphereShape(RADIUS);

    MyMotionState* motionState = new MyMotionState(startTransform);

    btVector3 fallInertia(0,0,0);
    fallShape->calculateLocalInertia(MASS, fallInertia);

    btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(MASS, motionState, fallShape, fallInertia);
    btRigidBody* rigidBody = new btRigidBody(fallRigidBodyCI);

    dynamicsWorld->addRigidBody(rigidBody);

    
    for (int frameCount = 1; ; ++frameCount)
    {
        dynamicsWorld->stepSimulation(SIM_DELAY);

        btTransform btt;
        rigidBody->getMotionState()->getWorldTransform(btt);
        std::cout << "Frame stepped.... Actual Y position: " << btt.getOrigin().getY() << std::endl;

        if (frameCount % 3 == 0) // every few frames, try to reset rigidbody's MotionState
        {
            std::cout << "Resetting position..." << std::endl;
            btTransform bttReset;
            bttReset.setIdentity();
            bttReset.setOrigin(btVector3(DEFAULT_X, DEFAULT_Y, DEFAULT_Z));
            rigidBody->getMotionState()->setWorldTransform(bttReset);
        }

        Sleep(SLEEP_DELAY);
    }
    
}
And here's the ouput:

Code: Select all

getWorldTransform called... Y: 9.98611
Frame stepped.... Actual Y position: 9.98611
setWorldTransform called... Y: 9.975
getWorldTransform called... Y: 9.975
Frame stepped.... Actual Y position: 9.975
Resetting position...
setWorldTransform called... Y: 10
setWorldTransform called... Y: 9.96111
getWorldTransform called... Y: 9.96111
Frame stepped.... Actual Y position: 9.96111
setWorldTransform called... Y: 9.94445
getWorldTransform called... Y: 9.94445
Frame stepped.... Actual Y position: 9.94445
setWorldTransform called... Y: 9.92501
getWorldTransform called... Y: 9.92501
Frame stepped.... Actual Y position: 9.92501
Resetting position...
setWorldTransform called... Y: 10
setWorldTransform called... Y: 9.90279
getWorldTransform called... Y: 9.90279
Frame stepped.... Actual Y position: 9.90279
setWorldTransform called... Y: 9.87779
getWorldTransform called... Y: 9.87779
Frame stepped.... Actual Y position: 9.87779
...
I've run a similar simulation using a falling dynamic rigid body in which the body lands and bounces on a static rigid body. If I let the simulation run long enough for the dynamic body to come to a rest, I can set the transform and it holds between frames. Unfortunately, once I can do this, stepping the simulation doesn't affect the transform anymore. Is it possible to "restart" the simulation at that point so that further calls to stepSimulation affect the repositioned dynamic rigid body?
Jasonrun
Posts: 11
Joined: Fri Oct 30, 2009 7:44 pm

Re: Manually positioning dynamic rigid bodies with setWorldTr...

Post by Jasonrun »

This bit works for me:

Code: Select all

rigidBody->getWorldTransform().setIdentity();
rigidBody->getWorldTransform().setOrigin(btVector3(DEFAULT_X, DEFAULT_Y, DEFAULT_Z));
instead of your

Code: Select all

btTransform bttReset;
bttReset.setIdentity();
bttReset.setOrigin(btVector3(DEFAULT_X, DEFAULT_Y, DEFAULT_Z));
rigidBody->getMotionState()->setWorldTransform(bttReset);
But keep in mind that the velocity is not affected by this, so it will continue to grow faster and the object will fall further and further by the next step.

Once the object stops it gets set to a sleeping state, you can wake it up with

Code: Select all

rigidBody->activate(true);
a8sdyf98as
Posts: 2
Joined: Sat Nov 14, 2009 3:52 pm

Re: Manually positioning dynamic rigid bodies with setWorldTr...

Post by a8sdyf98as »

Thanks Jasonrun! You've cleared up all of my concerns. I really appreciate it!