Repeating the same state between simulation steps?

sparkprime
Posts: 508
Joined: Fri May 30, 2008 2:51 am
Location: Ossining, New York

Repeating the same state between simulation steps?

Post by sparkprime »

Hi, I'm a brand new Bullet user as of 3 hours ago. I'm new to physics engines in general, too. The first thing I've tried to do is the following: (code is public domain in case anyone wants it)

Code: Select all

#include <cstdlib>
#include <algorithm>
#include <iostream>

#include <btBulletDynamicsCommon.h>

class PhysicsWorld {

    public:

        PhysicsWorld ()
        {
                col_conf = new btDefaultCollisionConfiguration();
                col_disp = new btCollisionDispatcher(col_conf);

                // first 2 params specify the world AABB
                // last param is the max number of "proxies"
                broadphase = new btAxisSweep3(btVector3(-1000,-1000,-1000),btVector3(1000,1000,1000),32766);

                con_solver = new btSequentialImpulseConstraintSolver();

                world = new btDiscreteDynamicsWorld(col_disp,broadphase,con_solver,col_conf);

                world->setGravity(btVector3(0,0,-9.8));
        }

        virtual ~PhysicsWorld ()
        {

                for (int i=world->getNumCollisionObjects()-1 ; i>=0 ; --i) {

                        btCollisionObject* obj =
                                world->getCollisionObjectArray()[i];

                        btRigidBody* victim = btRigidBody::upcast(obj);

                        if (victim==NULL) continue;

                        deleteBody(victim);
                }


                delete world;
                delete con_solver;
                delete broadphase;
                delete col_disp;
                delete col_conf;
        }

        btRigidBody *createBody (btCollisionShape *shape, float mass, float ccd_motion_thresh, btMotionState* motion = NULL)
        {

                btVector3 local_inertia(0,0,0);
                if (mass != 0)
                        shape->calculateLocalInertia(mass,local_inertia);

                btRigidBody::btRigidBodyConstructionInfo cInfo(mass, motion, shape, local_inertia);

                btRigidBody* body = new btRigidBody(cInfo);

                world->addRigidBody(body);

                // Only do CCD if  motion in one timestep (1.f/60.f) exceeds this
                body->setCcdSquareMotionThreshold(ccd_motion_thresh);

                //Experimental: better estimation of CCD Time of Impact:
                //body->setCcdSweptSphereRadius( 0.2*0.5 );

                return body;
        }

        void deleteBody (btRigidBody *victim)
        {
                world->removeRigidBody(victim);

                btMotionState* motion = victim->getMotionState();
                delete motion;

                delete victim;
        }

        btBoxShape *createBox (float lx, float ly, float lz)
        {
                btBoxShape *r = new btBoxShape (btVector3(lx,ly,lz));
                r->setMargin(0.05);
                return r;
        }

        btCylinderShape *createCylinder (float lx, float ly, float lz)
        {
                btCylinderShape *r = new btCylinderShape(btVector3(lx,ly,lz));
                r->setMargin(0.05);
                return r;
        }

        int pump (float seconds)
        {
                //during idle mode, just run 1 simulation step maximum
                return world->stepSimulation(seconds,100000);
        }

    protected:

        btDefaultCollisionConfiguration *col_conf;
        btCollisionDispatcher *col_disp;

        btBroadphaseInterface *broadphase;

        btConstraintSolver *con_solver;

        btDiscreteDynamicsWorld *world;


        // add some objects


};

class MotionCallback : public btMotionState {

    protected:

        btVector3 initialPos;
        int counter;

    public:

        MotionCallback (float x, float y, float z)
              : initialPos(x,y,z), counter(0)
        { }

        virtual void getWorldTransform (btTransform& into_here) const
        {
                into_here.setIdentity();
                into_here.setOrigin(initialPos);
        }

        virtual void setWorldTransform (const btTransform& current_xform)
        {
                std::cout << counter++ << " " << current_xform.getOrigin().z() << std::endl;
        }

};

int main (void)
{

        PhysicsWorld *pw = new PhysicsWorld();

        btCollisionShape *floor = pw->createBox(200,200,0.5);
        btCollisionShape *cylinder = pw->createCylinder(0.5,0.5,0.5);

        pw->createBody(floor, 0, 0.5, NULL);
        pw->createBody(cylinder, 1, 0.5, new MotionCallback(0,0,10));

        for (int i=0 ; i<2 ; ++i) {
                pw->pump(1);
        }

        delete pw;

        delete floor;
        delete cylinder;

        return EXIT_SUCCESS;
}
All it does is to drop a cylinder from 10m and have it collide with the floor, a flat plane. I graph the output and I get:

Image

Two things, the "kink" at the 60th iteration, i.e. at the edge of calls to world->stepSimulation(...), is it supposed to be there? Can I get rid of it?

The slight penetration at the end of the fall, why does this happen? Can I get rid of it?

Thanks.
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: Repeating the same state between simulation steps?

Post by Erwin Coumans »

The "kink" or discontinuity is likely due to internal fixed time step of 60 Hertz; it might run a different number of internal substeps. You can prevent this by passing 0 as second argument to stepSimulation, or using a smaller internal fixed timestep as third argument. This is not recommended for real-time simulation, Bullet works better with an internal fixed timestep.

The slight penetration happens because Bullet is currently only using discrete collision detection in btDiscreteDynamicsWorld. We will enable btContinuousDynamicsWorld, that should prevent (deep) penetration. Another way of reducing this effects is by passing a third argument to the stepSimulation, using a very small internal fixed timestep, for example:

Code: Select all

return world->stepSimulation(seconds,500,1./240.f);
Hope this helps,
Erwin
sparkprime
Posts: 508
Joined: Fri May 30, 2008 2:51 am
Location: Ossining, New York

Re: Repeating the same state between simulation steps?

Post by sparkprime »

Thanks for your reply!

If it doesn't run an internal substep it's supposed to interpolate isn't it? At the moment it's just repeating the last recorded position at the beginning of the next call to stepSimulation(...). I tried all sorts of things, including 0 as a second parameter. In that case, there is 1 repeated state for every new state. I was never able to eliminate it, but diminished it by maximising the number of implicit steps behind stepSimulation, as in the screenshot where there are 60 real ticks per stepSimulation call.
sparkprime
Posts: 508
Joined: Fri May 30, 2008 2:51 am
Location: Ossining, New York

Re: Repeating the same state between simulation steps?

Post by sparkprime »

Using a small internal timestep did indeed decrease the penetration :)

Am I not using any CCD stuff at the moment then? Do I want a different type of world?
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: Repeating the same state between simulation steps?

Post by Erwin Coumans »

If it doesn't run an internal substep it's supposed to interpolate isn't it?
Yes, Bullet automatically interpolates, but you are required to use the world transform from the motion state, not directly from the rigid body. Check out CcdPhysicsDemo, press on 'i' and run single steps using the 's' key to see the interpolation effect.

stepSimulation returns the number of actual simulation substeps executed.
Am I not using any CCD stuff at the moment then? Do I want a different type of world?
You probably want to wait until the btContinuousDynamicsWorld is completed, it is under development. Or work on your own continuous physics response, using Bullet continuous collision detection.

Thanks,
Erwin
sparkprime
Posts: 508
Joined: Fri May 30, 2008 2:51 am
Location: Ossining, New York

Re: Repeating the same state between simulation steps?

Post by sparkprime »

I still don't understand why I get 2 callbacks for each call to stepSimulation (1,0,1), with the same transform in each...