[Solved] Problems when projecting segment onto OBB axis.

This topic is 3177 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Here is the ray/intersection test I am using:
            // Turn ray into segment
Vector3 A = Origin;
Vector3 B = Origin + Direction * 1000.0f;        // Max length of ray (can be reduced)

// Segment mid point
Vector3 m = (A + B) * 0.5f;

// Segment halflength vector
Vector3 d = A - m;

// Translate OBB and segment to origin
m = m - oBB.Centre;

// Project the segment onto the separating axes
float adx = Math.Abs(Vector3.Dot(oBB.Axis_X, d));
float ady = Math.Abs(Vector3.Dot(oBB.Axis_Y, d));
float adz = Math.Abs(Vector3.Dot(oBB.Axis_Z, d));

// Obb axes are othogonal
Console.WriteLine(Vector3.Cross(oBB.Axis_X, oBB.Axis_Y));
Console.WriteLine(oBB.Axis_Z);

// Try world coordinates as separating values
if (Math.Abs(m.X) > oBB.Extents.X + adx)
{
return false;
}
if (Math.Abs(m.Y) > oBB.Extents.Y + ady)
{
return false;
}
if (Math.Abs(m.Z) > oBB.Extents.Z + adz)
{
return false;
}

// Add in an epsilon term to counteract arithmetic errors when segment is (near parallel to a coordinate axis

// Try cross products of segment direction vector with coordinate axes
if (Math.Abs(m.Y * d.Z - m.Z * d.Y) > oBB.Extents.Y * adz + oBB.Extents.Z * ady)
{
return false;
}
if (Math.Abs(m.Z * d.X - m.X * d.Z) > oBB.Extents.X * adz + oBB.Extents.Z * adx)
{
return false;
}
if (Math.Abs(m.X * d.Y - m.Y * d.X) > oBB.Extents.X * ady + oBB.Extents.Y * adx)
{
return false;
}

return true;


The problem is the intersection test is not returning true when the OBB rotation is anything but axis aligned (Matrix.Identity). Have the following lines not projected the ray/segment onto the OBB axes correctly: // Project the segment onto the separating axes float adx = Math.Abs(Vector3.Dot(oBB.Axis_X, d)); float ady = Math.Abs(Vector3.Dot(oBB.Axis_Y, d)); float adz = Math.Abs(Vector3.Dot(oBB.Axis_Z, d)); Or have I made a different mistake entirely? Thank you. [Edited by - Spa8nky on November 10, 2009 9:41:44 AM]

Share on other sites
Ok, I've now solved the problem but I have another:

When returning the surface normal of the OBB from a given point, is the following correct:

        /// <summary>        /// Return the surface normal for any given point on the OBB        /// </summary>        /// <param name="point"></param>        /// <returns></returns>        public Vector3 GetNormalFromPoint(Vector3 point)        {            Vector3 normal = Vector3.Zero;            float min = float.MaxValue;            float distance;            point -= Centre;            distance = Math.Abs(Extents.X - Math.Abs(point.X));            if (distance < min)            {                min = distance;                normal = Math.Sign(point.X) * Axis_X;       // Rotation.M11, Rotation.M12, Rotation.M13            }            distance = Math.Abs(Extents.Y - Math.Abs(point.Y));            if (distance < min)            {                min = distance;                normal = Math.Sign(point.Y) * Axis_Y;       // Rotation.M21, Rotation.M22, Rotation.M23            }            distance = Math.Abs(Extents.Z - Math.Abs(point.Z));            if (distance < min)            {                min = distance;                normal = Math.Sign(point.Z) * Axis_Z;       // Rotation.M31, Rotation.M32, Rotation.M33            }            return normal;        }

If not, then please feel free to scorn :)

Thanks

EDIT: The method above isn't correct :(

[Edited by - Spa8nky on November 9, 2009 7:47:55 PM]

Share on other sites
I got it, woohoo!

        /// <summary>        /// Return the surface normal for any given point on the OBB        /// </summary>        /// <param name="point"></param>        /// <returns></returns>        public Vector3 GetNormalFromPoint(Vector3 point)        {            Vector3 normal = Vector3.Zero;            float min = float.MaxValue;            float distance;            point -= Centre;            // Compute translation vector t            Vector3 t = point - Centre;            t.X = Vector3.Dot(point, Axis_X);            t.Y = Vector3.Dot(point, Axis_Y);            t.Z = Vector3.Dot(point, Axis_Z);            distance = Math.Abs(Extents.X - Math.Abs(t.X));            if (distance < min)            {                min = distance;                normal = Math.Sign(t.X) * Axis_X;       // Rotation.M11, Rotation.M12, Rotation.M13            }            distance = Math.Abs(Extents.Y - Math.Abs(t.Y));            if (distance < min)            {                min = distance;                normal = Math.Sign(t.Y) * Axis_Y;       // Rotation.M21, Rotation.M22, Rotation.M23            }            distance = Math.Abs(Extents.Z - Math.Abs(t.Z));            if (distance < min)            {                min = distance;                normal = Math.Sign(t.Z) * Axis_Z;       // Rotation.M31, Rotation.M32, Rotation.M33            }            return normal;        }

Seems to work just fine! Any comments?

Share on other sites
Just that
Vector3 t = point - Centre;
is overwritten immediately after that line. So I assume that
Vector3 t;
would be already sufficient.

Share on other sites
Oh yes, thank you.

The code now reads as follows:

        /// <summary>        /// Return the surface normal for any given point on the OBB        /// </summary>        /// <param name="point"></param>        /// <returns></returns>        public Vector3 GetNormalFromPoint(Vector3 point)        {            Vector3 normal = Vector3.Zero;            float min = float.MaxValue;            float distance;            // Compute translation vector t            point -= Centre;            Vector3 t;            // Bring translation into OBB's coordinate frame            t.X = Vector3.Dot(point, Axis_X);            t.Y = Vector3.Dot(point, Axis_Y);            t.Z = Vector3.Dot(point, Axis_Z);            distance = Math.Abs(Extents.X - Math.Abs(t.X));            if (distance < min)            {                min = distance;                normal = Math.Sign(t.X) * Axis_X;       // Rotation.M11, Rotation.M12, Rotation.M13            }            distance = Math.Abs(Extents.Y - Math.Abs(t.Y));            if (distance < min)            {                min = distance;                normal = Math.Sign(t.Y) * Axis_Y;       // Rotation.M21, Rotation.M22, Rotation.M23            }            distance = Math.Abs(Extents.Z - Math.Abs(t.Z));            if (distance < min)            {                min = distance;                normal = Math.Sign(t.Z) * Axis_Z;       // Rotation.M31, Rotation.M32, Rotation.M33            }            return normal;        }

I think this is about as straight forward as I can make this method. If I try simplifying it:

            // Compute translation vector t            Vector3 t = point - Centre;            // Bring translation into OBB's coordinate frame            t.X = Vector3.Dot(t, Axis_X);            t.Y = Vector3.Dot(t, Axis_Y);            t.Z = Vector3.Dot(t, Axis_Z);

The code won't work as I am changing t each time.

1. 1
2. 2
3. 3
Rutin
19
4. 4
5. 5

• 14
• 30
• 13
• 11
• 11
• Forum Statistics

• Total Topics
631780
• Total Posts
3002314
×