Box2d - Possible to get rid of accumulated impulses?
-
- Posts: 49
- Joined: Fri Aug 18, 2006 11:50 pm
Box2d - Possible to get rid of accumulated impulses?
Iv been messing around with box2d and it seems that simply creating a new contact each step instead of updating an existing one makes it go a bit faster. THis of coarse makes the accumulated impulses 0 which leads to inaccuracy...
My question is, is there any way to make it more stable without using any sort of accumulated impulse? (calculating the impulse from scratch each frame)
Edit:
I also realize that the code added to compensate for not having the accumulated impulse would probably make it go slower, but im still interested to know if there is any way of doing it
My question is, is there any way to make it more stable without using any sort of accumulated impulse? (calculating the impulse from scratch each frame)
Edit:
I also realize that the code added to compensate for not having the accumulated impulse would probably make it go slower, but im still interested to know if there is any way of doing it
-
- Posts: 316
- Joined: Fri Jul 01, 2005 5:29 am
- Location: Irvine
-
- Posts: 49
- Joined: Fri Aug 18, 2006 11:50 pm
Speed is not really a concern for me, im just interesting in getting stable stacking without accumulating any impulses. I dont plan to actually use it for anything in particular, its just for me to learn from
Getting rid of the accumulation does indeed make the stacking unstable, but theres gota be a way to go without them and still have stable stacking..
When i get rid of them (simply dont transfer it over when an arbiter is updated), the boxes dont penetrate each other, but the stacks will sway, slide on each other and eventually topple over
If there is no way to do without them, could you recommend a contact solving method that does not require and frame to frame knolledge but also has stable stacking and accurate behaviour?
Getting rid of the accumulation does indeed make the stacking unstable, but theres gota be a way to go without them and still have stable stacking..
When i get rid of them (simply dont transfer it over when an arbiter is updated), the boxes dont penetrate each other, but the stacks will sway, slide on each other and eventually topple over
If there is no way to do without them, could you recommend a contact solving method that does not require and frame to frame knolledge but also has stable stacking and accurate behaviour?
-
- Posts: 316
- Joined: Fri Jul 01, 2005 5:29 am
- Location: Irvine
The solver is trying to solve a nonlinear system of equations iteratively. By using accumulated impulses, it is able to spread the cost of an accurate solution over several time steps.
What you are trying to do is achieve the same accuracy within a single time step. I don't know how to do this without a huge additional cost.
What you are trying to do is achieve the same accuracy within a single time step. I don't know how to do this without a huge additional cost.
-
- Posts: 49
- Joined: Fri Aug 18, 2006 11:50 pm
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
Hi,
I think it's better to distinguish two separate/different concepts: accumulating the impulse during the iterations. And secondly, 'warmstarting': assigning the previous frames values for the accumulated impulse at the start of the frame.
I have good stacking results in Bullet (in 3D) even when warmstarting is disabled (in fact, it is disabled by default at the moment). ODE also has no warmstarting (all contact points are re-created every frame), and no stacking issues there. So I'm curious how many iterations you use? How do you create the contact ponts? What timestep? fixed/variable? And also, what friction model do you use? How do you interleave friction with contact impulses, and what value do you use for friction: based on normal impulse of this iteration, or accumulated impulse?
Thanks,
Erwin
I think it's better to distinguish two separate/different concepts: accumulating the impulse during the iterations. And secondly, 'warmstarting': assigning the previous frames values for the accumulated impulse at the start of the frame.
I have good stacking results in Bullet (in 3D) even when warmstarting is disabled (in fact, it is disabled by default at the moment). ODE also has no warmstarting (all contact points are re-created every frame), and no stacking issues there. So I'm curious how many iterations you use? How do you create the contact ponts? What timestep? fixed/variable? And also, what friction model do you use? How do you interleave friction with contact impulses, and what value do you use for friction: based on normal impulse of this iteration, or accumulated impulse?
Thanks,
Erwin
-
- Posts: 316
- Joined: Fri Jul 01, 2005 5:29 am
- Location: Irvine
Yes, a smaller time step would help.
Erwin, you are correct about the two concepts. I've been talking about warm starting.
In Box2D Demo 3:
dt = 1/60 (fixed), iterations = 10
Warm starting: the vertical stack is easily stable with 10 boxes
No warm starting: the vertical stack is not stable with only 3 boxes
To turn off warm starting:
Change Arbiter.cpp (66) from
if (k > -1)
To
if (false)
When testing stacking, be sure to test vertical stacks. Walls and pyramids are much more stable and don't reveal stability problems as well.
Stacking stability was one of the main problems I had with ODE's QuickStep algorithm. That is why I pursued warm starting.
Friction:
- point-wise
- dependent on accumulated normal impulse of the current iteration
- interleaved
Erwin, you are correct about the two concepts. I've been talking about warm starting.
In Box2D Demo 3:
dt = 1/60 (fixed), iterations = 10
Warm starting: the vertical stack is easily stable with 10 boxes
No warm starting: the vertical stack is not stable with only 3 boxes
To turn off warm starting:
Change Arbiter.cpp (66) from
if (k > -1)
To
if (false)
When testing stacking, be sure to test vertical stacks. Walls and pyramids are much more stable and don't reveal stability problems as well.
Stacking stability was one of the main problems I had with ODE's QuickStep algorithm. That is why I pursued warm starting.
Friction:
- point-wise
- dependent on accumulated normal impulse of the current iteration
- interleaved
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
I am suprised: Bullet's CcdPhysicsDemo has 2 stacks (1 single stack of 12 boxes, and one wall). The stacks are stable without warmstarting when using SequentialImpulse and ODE quickstep, 10 iterations, 60 hertz (this is not meant to brag: previously I wrongly clipped the incremental impulse instead of the accumulated, thanks to Erin).Erin Catto wrote:Stacking stability was one of the main problems I had with ODE's QuickStep algorithm. That is why I pursued warm starting.
Perhaps some other issue then? Every single piece of the puzzle seems to make a global impact on stability/convergence.
Erwin
-
- Posts: 49
- Joined: Fri Aug 18, 2006 11:50 pm
Ah I see, I think i may have confused my terms. Warmstarting is whay I want to get rid of and still have stable stacking. So ODE's quickstep does this without warmstarting? I thought that used LPC or somthing
So, to get stable stacking without warmstarting, does quickstep have to be used in conjunction with bullet's SequentialImpulse solver or can bullets solver already do that by itself?
So, to get stable stacking without warmstarting, does quickstep have to be used in conjunction with bullet's SequentialImpulse solver or can bullets solver already do that by itself?
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
Stable stacking can be done in Bullet using one of the 2 constraint solvers. They both work fine, and are mathematically equivalent (they are both iterative LCP solvers).
Bullet's default constraint solver is the Sequential Impulse solver, see Bullet/src/BulletDynamics/Constraint/btSequentialConstraintSolver.cpp. The other solver can be found easily in Extras. You choose one of the two. Simple.
Erwin
Bullet's default constraint solver is the Sequential Impulse solver, see Bullet/src/BulletDynamics/Constraint/btSequentialConstraintSolver.cpp. The other solver can be found easily in Extras. You choose one of the two. Simple.
Erwin
coderchris wrote:Ah I see, I think i may have confused my terms. Warmstarting is whay I want to get rid of and still have stable stacking. So ODE's quickstep does this without warmstarting? I thought that used LPC or somthing
So, to get stable stacking without warmstarting, does quickstep have to be used in conjunction with bullet's SequentialImpulse solver or can bullets solver already do that by itself?
-
- Posts: 49
- Joined: Fri Aug 18, 2006 11:50 pm
-
- Posts: 316
- Joined: Fri Jul 01, 2005 5:29 am
- Location: Irvine
I modified appCcdPhysicsDemo in Bullet 2.30 to be roughly equivalent to Box2D Demo 3. Is warm starting on in this version? I couldn't stack more than 7 boxes. Also, there is some high frequency jitter.
It is quite difficult to turn off deactivation in Bullet. I had to do it through the debug draw mode, but this gets messed up when I press z or x. Could this be made easier?
It is quite difficult to turn off deactivation in Bullet. I had to do it through the debug draw mode, but this gets messed up when I press z or x. Could this be made easier?
Code: Select all
#include "btBulletDynamicsCommon.h"
#include "LinearMath/btIDebugDraw.h"
#include "GLDebugDrawer.h"
#include <stdio.h>
#include "CcdPhysicsDemo.h"
#include "GL_ShapeDrawer.h"
#include "GlutStuff.h"
float deltaTime = 1.f/60.f;
float gCollisionMargin = 0.05f;
const int maxProxies = 32766;
const int gNumObjects = 8;
#define CUBE_HALF_EXTENTS 0.5f
GLDebugDrawer debugDrawer;
btCollisionShape* shapePtr[] =
{
new btBoxShape(btVector3(50,10,50)),
new btBoxShape(btVector3(CUBE_HALF_EXTENTS, CUBE_HALF_EXTENTS, CUBE_HALF_EXTENTS)),
};
int main(int argc,char** argv)
{
//experimental jitter damping (1 = no damping, 0 = total damping once motion below threshold)
extern float gJitterVelocityDampingFactor;
gJitterVelocityDampingFactor = 0.7f;
debugDrawer.setDebugMode(btIDebugDraw::DBG_NoDeactivation);
CcdPhysicsDemo* ccdDemo = new CcdPhysicsDemo();
ccdDemo->initPhysics();
ccdDemo->setCameraDistance(12.f);
return glutmain(argc, argv,640,480,"Bullet Physics Demo. http://bullet.sf.net",ccdDemo);
}
void CcdPhysicsDemo::clientMoveAndDisplay()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (m_dynamicsWorld)
{
m_dynamicsWorld->stepSimulation(deltaTime,1);
}
renderme();
glFlush();
glutSwapBuffers();
}
void CcdPhysicsDemo::displayCallback(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_dynamicsWorld->updateAabbs();
renderme();
glFlush();
glutSwapBuffers();
}
inline float Random(float lo, float hi)
{
float r = (float)rand();
r /= RAND_MAX;
r = (hi - lo) * r + lo;
return r;
}
void CcdPhysicsDemo::initPhysics()
{
btCollisionDispatcher* dispatcher = new btCollisionDispatcher();
btVector3 worldAabbMin(-10000,-10000,-10000);
btVector3 worldAabbMax(10000,10000,10000);
btOverlappingPairCache* broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,maxProxies);
btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;
m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver);
m_dynamicsWorld->setGravity(btVector3(0,-10,0));
m_dynamicsWorld->setDebugDrawer(&debugDrawer);
btTransform tr;
tr.setIdentity();
for (int i=0; i<gNumObjects; i++)
{
bool isDyna = i>0;
btCollisionShape* shape = isDyna ? shapePtr[1] : shapePtr[0];
shape->setMargin(gCollisionMargin);
btTransform trans;
trans.setIdentity();
if (isDyna)
{
float x = Random(-0.1f, 0.1f);
float z = Random(-0.1f, 0.1f);
btVector3 pos(x, 0.55f + 1.1f * (i - 1.0f) - 10.0f, z);
trans.setOrigin(pos);
}
else
{
trans.setOrigin(btVector3(0,-20,0));
}
float mass = isDyna ? 1.f : 0.0f;
btRigidBody* body = localCreateRigidBody(mass,trans,shape);
body->setFriction(0.3f);
body->setRestitution(0.0f);
body->setDamping(0.0f, 0.0f);
body->setCcdSquareMotionThreshold( CUBE_HALF_EXTENTS );
body->setCcdSweptSphereRadius( 0.2*CUBE_HALF_EXTENTS );
}
clientResetScene();
}
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
In the demos, you can just press 'd' to toggle deactivation. But you are right, a proper API for that would be better.Erin Catto wrote: It is quite difficult to turn off deactivation in Bullet. I had to do it through the debug draw mode, but this gets messed up when I press z or x. Could this be made easier?
OK, I see how you make conditions worse then my default: random positions instead of a perfect aligned stack makes things a little worse indeed. Also letting the boxes fall down makes things already collapse before settling down, so just takine 0.5 + 1 * i works better. Smaller box sizes are less slightly less stable (I use 1 meter boxes, you use 0.5 meter). Bullet always uses internal timestep of 60 hertz, and interpolates transforms when passing real-time delta times. So you can just pass the realtime as first argument, instead of 1./60. Otherwise it just looks like the stack collapses soon, but it takes thousands of frames in real.
I took your demo, and without the 'random' the stack can be higher, 10 boxes at least without warmstarting, with it is about 7 indeed.
Erwin
-
- Posts: 49
- Joined: Fri Aug 18, 2006 11:50 pm
so, basically I can either warmstart, or not warmstart and suffer the consiquences of un-stable stacking.
I read something somewhere about "shock propagation" Supposedly that lets you have fairly stable stacking. I was unable to find any articles describing how to do it, would you happen to have any links?
I read something somewhere about "shock propagation" Supposedly that lets you have fairly stable stacking. I was unable to find any articles describing how to do it, would you happen to have any links?
-
- Posts: 197
- Joined: Sat Aug 19, 2006 11:52 pm
this might be a stupid question, but why wouldn't you want to warmstart?
my (limited) understanding is that by warmstarting you're just using the solution calculated by the previous frame as the initial guess for the current frame.. which seems like it would always be a better idea/closer to the current solution than just always using 0 as an initial guess.
my (limited) understanding is that by warmstarting you're just using the solution calculated by the previous frame as the initial guess for the current frame.. which seems like it would always be a better idea/closer to the current solution than just always using 0 as an initial guess.