Incorrect collision normal in sphere/triangle mesh collision
Posted: Sat Jun 18, 2016 1:17 pm
Hi,
in our game supertuxkart we've recently added a soccer mode. But during testing we discovered that now and again the ball would suddenly jump up a bit. The ground is a totally flat rectangle (>90x170 units) made out of 8x8 triangles (originally we used 2 triangles, but I seemed to remember some issues with large triangles in bullet, so we subdivded the plane - but it made no difference).
Debugging showed that this appears to happen during the constraint impulse solver, and is ultimately caused by bullet reporting a collision normal that is not (0,1,0), but slightly rotated e.g. (-0.191352 0.981521 0.00000). What happens later is that this normal is multiplied by the velocity of the object (ball) in btSequentialImpulseConstraintSolver::setupContactConstraint:
If the velocity of the ball in the direction of the incorrect normal (in the example above X direction) is high, the resulting value of rel_vel is too high, causing too big an impulse to be applied in btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowerLimit. This impulse is applied in the direction of the normal, which is mostly up --> the ball jumps up.
The incorrect normal is computed in SpheretriangleDetector::collide():
In case that distanceSqr>SIMD_EPSILON a new normal is computed as difference between the centre of the sphere and the collision point, which is in general not in the up direction of the triangle mesh.
A simple fix seems to be (as shown above) to set resultNormal to 'normal' (which is in our case (0, 1, 0)), but I am not sure what kind of side effect this could have.
Note that we are using a quite old version of bullet (2.79), but updating bullet is not a trivial issue for us (due to some modifications we have applied). I had a quick look at 2.83, and while a lot of source code has changed, the basic behaviour (i.e. computing the normal, multiplying with speed and applying the impulse) appears to be the same.
Can anyone with a better understanding shed some light on this issue? Is there a better fix then the one above? Or should we update to a current bullet version?
We see the same issue when using a puck (cylinder), but I haven't had time to debug this.
Any help appreciated!
Cheers,
Joerg
in our game supertuxkart we've recently added a soccer mode. But during testing we discovered that now and again the ball would suddenly jump up a bit. The ground is a totally flat rectangle (>90x170 units) made out of 8x8 triangles (originally we used 2 triangles, but I seemed to remember some issues with large triangles in bullet, so we subdivded the plane - but it made no difference).
Debugging showed that this appears to happen during the constraint impulse solver, and is ultimately caused by bullet reporting a collision normal that is not (0,1,0), but slightly rotated e.g. (-0.191352 0.981521 0.00000). What happens later is that this normal is multiplied by the velocity of the object (ball) in btSequentialImpulseConstraintSolver::setupContactConstraint:
Code: Select all
btVector3 vel1 = rb0 ? rb0->getVelocityInLocalPoint(rel_pos1) : btVector3(0,0,0);
btVector3 vel2 = rb1 ? rb1->getVelocityInLocalPoint(rel_pos2) : btVector3(0,0,0);
vel = vel1 - vel2;
rel_vel = cp.m_normalWorldOnB.dot(vel);
The incorrect normal is computed in SpheretriangleDetector::collide():
Code: Select all
...
if (hasContact) {
btVector3 contactToCentre = sphereCenter - contactPoint;
btScalar distanceSqr = contactToCentre.length2();
if (distanceSqr < radiusWithThreshold*radiusWithThreshold)
{
if (distanceSqr>SIMD_EPSILON)
{
btScalar distance = btSqrt(distanceSqr);
resultNormal = contactToCentre; // Incorrect normal here!
resultNormal.normalize();
// FIX??? resultNormal = normal;
point = contactPoint;
depth = -(radius-distance);
} else
{
btScalar distance = 0.f;
resultNormal = normal;
point = contactPoint;
depth = -radius;
}
return true;
}
A simple fix seems to be (as shown above) to set resultNormal to 'normal' (which is in our case (0, 1, 0)), but I am not sure what kind of side effect this could have.
Note that we are using a quite old version of bullet (2.79), but updating bullet is not a trivial issue for us (due to some modifications we have applied). I had a quick look at 2.83, and while a lot of source code has changed, the basic behaviour (i.e. computing the normal, multiplying with speed and applying the impulse) appears to be the same.
Can anyone with a better understanding shed some light on this issue? Is there a better fix then the one above? Or should we update to a current bullet version?
We see the same issue when using a puck (cylinder), but I haven't had time to debug this.
Any help appreciated!
Cheers,
Joerg