Wednesday, April 10, 2013

Be careful when dealing with C++ floating point.

Look at this piece of code:

Vector3 colPlaneNor;

float dx = abs(aabb1->getPosition().x() - aabb2->getPosition().x());
float dy = abs(aabb1->getPosition().y() - aabb2->getPosition().y());

if(dx < (aabb1->_width + obb2->_width)/2.0f)

    colPlaneNor = Vector3::UNIT_Y;
else if(dy < (aabb1->_height + aabb2->_height)/2.0f)
    colPlaneNor = Vector3::UNIT_X;

The idea of these lines of code is to determine the collision plane normal when two AABB boxes collided. The problem here is, floating point calculation is not 100% accurate. Even if the true is

dx == (aabb1->_width + obb2->_width)/2.0f,
 and
dy < (aabb1->_height + aabb2->_height)/2.0f

But in C++, the floating point number dx may slightly less than
(aabb1->_width + obb2->_width ) / 2.0f

That will cause the code pass the if()test first and set the collision plane normal to a wrong vector.
My solution here is to make the threshold a little bit lower:


if(dx < (aabb1->_width + aabb2->_width)*.99f/2.0f)
    colPlaneNor = Vector3::UNIT_Y;
else if(dy < (aabb1->_height + aabb2->_height)*.99f/2.0f)
    colPlaneNor = Vector3::UNIT_X;

Instead of compare the actual sum, I multiply the sum by 0.99. So even if dx is slightly lower than the actual result, it won't pass the if() test and jump into the else if(). If the collision plane normal should be normal Y, dy should still smaller (aabb1->_height + aabb2->_height)*.99f/2.0f.
If both dx and dy are actually equal to the sums, that means the two AABB is colliding on the coner, or maybe very closed to the corner. In this case I can make a default vector for the collision plane normal, such as normal X.

No comments:

Post a Comment