Sign in to follow this  
Spa8nky

OBB rotations affecting penetration depth along y axis. Is OBB class incorrect?

Recommended Posts

I have an OBB class that has the following:
        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;
        }

I can then derive the world transform for the OBB as the following:
                    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;
        }

and the 1D test for intersection for each separating axis should also be correct, as it works for other shapes:
        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;
        }

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.

Share this post


Link to post
Share on other sites
Have you tried with mirrored orientations? Do you find the bug with the x/z axes as well? Does the issue appear if the orientation of on object only differs on the y axis? If that works OK, assume the error is with the rotation code, or the projection onto the separating axis.


float a_Min = float.MaxValue;
float a_Max = float.MinValue;
float b_Min = float.MaxValue;
float b_Max = float.MinValue;


what is supposed to happen here?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this