Original Post
I have an OBB class that has the following: I can then derive the world transform for the OBB as the following: and the 1D test for intersection for each separating axis should also be correct, as it works for other shapes: I've stepped through the code and the problem is that the mtv_Distance is too small a value, which doesn't resolve the OBB penetration. Can anyone point out any glaring errors in my code so far, it would really help me as I can't understand why this is happening. Thank you.
Vector3[] axes; // Local x, y and z axes
Vector3 extents; // Positive halfwidth extents of the OBB along each axis
Quaternion orientation = Quaternion.Identity; // Orientation of OBB (Rotation matrix is derived from this)
Vector3 position;
Matrix rotation;
If I want to update the orientation of the OBB then I do the following:
public void UpdateRotation(float yaw, float pitch, float roll)
{
if (yaw == 0f && pitch == 0f && roll == 0f)
{
return;
}
Quaternion rotation_Additional = Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll);
orientation *= rotation_Additional;
orientation.Normalize();
rotation = Matrix.CreateFromQuaternion(orientation);
// Local X, Y and Z axes
axes[0] = rotation.Right;
axes[1] = rotation.Up;
axes[2] = rotation.Forward;
recreateWorld = true;
}
world_Transform =
Matrix.CreateScale(extents * 2f) *
rotation *
Matrix.CreateTranslation(position);
Can anyone tell me if what I have got is incorrect in any way please? The reason why I ask is because I trying to locate the source of an irritating collision response bug that occurs between 2 OBBs intersecting along the Y-axis. The OBBs will resolve the collision correctly if they both have the same orientation, but the penetration depth is calculated too small if the orientations differ by even the slightest amount. I am calculating the OBB slabs correctly for intersections tests as follows:
public void CalculateSlab(Vector3 axis, ref float min, ref float max)
{
// • A slab is the infinite region of space between two planes
// • The min and max values are then the required scalar values defining the plane positions
float pos = Vector3.Dot(position, axis);
float ext =
Math.Abs(Vector3.Dot(axes[0], axis)) * extents.X +
Math.Abs(Vector3.Dot(axes[1], axis)) * extents.Y +
Math.Abs(Vector3.Dot(axes[2], axis)) * extents.Z;
min = pos - ext;
max = pos + ext;
}
private static bool IntersectThruAxis(Vector3 axis, CD_AABB a, CD_OBB b, ref float mtv_Distance, ref Vector3 mtv_Axis)
{
// [Separating Axis Theorem]
// • Two convex shapes only overlap if they overlap on all axes of separation
// • In order to create accurate responses we need to find the collision vector (Minimum Translation Vector)
// • Find if the two boxes intersect along a single axis
// • Compute the intersection interval for that axis
// • Keep the smallest intersection/penetration value
float a_Min = float.MaxValue;
float a_Max = float.MinValue;
float b_Min = float.MaxValue;
float b_Max = float.MinValue;
a.CalculateSlab(axis, ref a_Min, ref a_Max);
b.CalculateSlab(axis, ref b_Min, ref b_Max);
// Find distance intervals for current two slabs
// Distance is between slab min/max values
float d_S0 = a_Min - b_Max;
float d_S1 = b_Min - a_Max;
// The distance is positive if the intervals do not overlap
// Must be >= to 0 and not > 0, otherwise MTV can equal Vector3.Zero and cause NaN
if (d_S0 >= 0f || d_S1 >= 0f)
{
return false;
}
// Current distance interval for slabs [A_Min, A_Max] and [B_Min, B_Max]
float d = (d_S0 > d_S1) ? -d_S0 : d_S1;
// If d is the smallest distance so far
if (Math.Abs(d) < Math.Abs(mtv_Distance))
{
// Store the distance and the current axis
mtv_Distance = d;
mtv_Axis = axis;
}
return true;
}