Sign in to follow this  
Spa8nky

[Solved] Problems when projecting segment onto OBB axis.

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

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