Sign in to follow this  

[Solved] Problems when projecting segment onto OBB axis.

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

If you intended to correct an error in the post then please contact us.

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
            adx += GameConstants.EPSILON;
            ady += GameConstants.EPSILON;
            adz += GameConstants.EPSILON;

            // 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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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.



Share this post


Link to post
Share on other sites

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

If you intended to correct an error in the post then please contact us.

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