There are a few things to notice. First is the flickering of the contact points, indicating that contact points are occasionally dropped despite the contact processing threshold being set to 0.01m and the contact breaking threshold being set to 0.02m. Secondly, we can see that the boxes move at radically different speeds despite the friction coefficients all being set to 0.15.

1) First, I disabled SOLVER_RANDMIZE_ORDER:

The boxes still move about a little, but the boxes now all move at approximately the same speed.

2) Secondly, I set gContactCalcArea3Points to false.

The boxes now slide straight down the ramp as desired. There is still some contact point flickering, although this does not seem to adversely affect the behaviour.

----

After a little investigation, it appears as though the randomised constraint ordering code is adapted from ODE. However, unlike in ODE, the friction constraints are randomly shuffled so that the friction constraints for a given contact point do not correspond to the random ordering of the penetration constraints. To clarify, if I swap two penetration constraints for a pair of contact points then I expect to also swap the friction constraints for the pair of contact points. However, this is not the case. Currently, the penetration constraints are randomly shuffled. Then the friction constraints are randomly shuffled. This appears to have an adverse effect, as shown above.

My solution for this is to rewrite the constraint ordering:

Code: Select all

```
for (int j = 1; j < numConstraintPool; ++j) {
int tmp = m_orderTmpConstraintPool[j];
int swapi = btRandInt2(j + 1);
m_orderTmpConstraintPool[j] = m_orderTmpConstraintPool[swapi];
m_orderTmpConstraintPool[swapi] = tmp;
}
for (int j = 1; j < numFrictionPool; ++j) {
int tmp = m_orderFrictionConstraintPool[j];
int swapi = btRandInt2(j + 1);
m_orderFrictionConstraintPool[j] = m_orderFrictionConstraintPool[swapi];
m_orderFrictionConstraintPool[swapi] = tmp;
}
```

Code: Select all

```
int swapi = btRandInt2(j + 1);
{
int tmp = m_orderTmpConstraintPool[j];
m_orderTmpConstraintPool[j] = m_orderTmpConstraintPool[swapi];
m_orderTmpConstraintPool[swapi] = tmp;
}
if (infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)
{
int tmp1 = m_orderFrictionConstraintPool[j * 2];
int tmp2 = m_orderFrictionConstraintPool[j * 2 + 1];
m_orderFrictionConstraintPool[j * 2] = m_orderFrictionConstraintPool[swapi * 2];
m_orderFrictionConstraintPool[swapi * 2] = tmp1;
m_orderFrictionConstraintPool[j * 2 + 1] = m_orderFrictionConstraintPool[swapi * 2 + 1];
m_orderFrictionConstraintPool[swapi * 2 + 1] = tmp2;
}
else
{
int tmp = m_orderFrictionConstraintPool[j];
m_orderFrictionConstraintPool[j] = m_orderFrictionConstraintPool[swapi];
m_orderFrictionConstraintPool[j] = tmp;
}
```

----

Does anybody know why the contact points do not seem to persist?