Question

Ray OBB intersection not working. Ray not transformed into OBB space correctly?

Asked by: Dr_Spankenstein

I am trying to get a ray to return true when intersecting with an OBB.  My method works sound with an AABB but when I try it with an OBB then no intersection is ever returned.

I think that I have not transformed the ray into OBB space correctly and I have attached the code to show what I have so far:

            float t_Min = 0.0f;
 
            // Maximum distance ray can travel (makes it a segment, otherwise it would be infinite)
            float t_Max = float.MaxValue;
 
            float ood = 0.0f;
            float t1 = 0.0f;
            float t2 = 0.0f;
 
            // Translate ray to OBB space
            Vector3 min_Local = Origin - oBB.Position;      // (P - C)
            Vector3 max_Local = Origin - oBB.Position;      // (P - C)
 
            float min_X = Vector3.Dot(min_Local, oBB.Axis_X);
            float max_X = Vector3.Dot(max_Local, oBB.Axis_X);
            float min_Y = Vector3.Dot(min_Local, oBB.Axis_Y);
            float max_Y = Vector3.Dot(max_Local, oBB.Axis_Y);
            float min_Z = Vector3.Dot(min_Local, oBB.Axis_Z);
            float max_Z = Vector3.Dot(max_Local, oBB.Axis_Z);
 
            // For all 3 slabs
            if (Math.Abs(Direction.X) < float.Epsilon)
            {
                // Ray is parallel to slab.  No hit if origin (p in book) not within slab
                if (Origin.X < min_X || Origin.X > max_X)
                {
                    return false;
                }
            }
            else
            {
                // Compute intersection t value of ray with near and far plane of slab
                ood = 1.0f / Direction.X;
                t1 = (min_X - Origin.X) * ood;
                t2 = (max_X - Origin.X) * ood;
 
                // Make (t1) be intersection with near plane, (t2) with far plane
                if (t1 > t2)
                {
                    Swap(ref t1, ref t2);
                }
 
                // Compute the intersection of slab intersection intervals
                t_Min = Math.Max(t_Min, t1);
                t_Max = Math.Min(t_Max, t2);
 
                // Exit with no collision as soon as slab intersection becomes empty
                if (t_Min > t_Max)
                {
                    return false;
                }
            }
            if (Math.Abs(Direction.Y) < float.Epsilon)
            {
                // Ray is parallel to slab.  No hit if origin (p in book) not within slab
                if (Origin.Y < min_Y || Origin.Y > max_Y)
                {
                    return false;
                }
            }
            else
            {
                // Compute intersection t value of ray with near and far plane of slab
                ood = 1.0f / Direction.Y;
                t1 = (min_Y - Origin.Y) * ood;
                t2 = (max_Y - Origin.Y) * ood;
 
                // Make (t1) be intersection with near plane, (t2) with far plane
                if (t1 > t2)
                {
                    Swap(ref t1, ref t2);
                }
 
                // Compute the intersection of slab intersection intervals
                t_Min = Math.Max(t_Min, t1);
                t_Max = Math.Min(t_Max, t2);
 
                // Exit with no collision as soon as slab intersection becomes empty
                if (t_Min > t_Max)
                {
                    return false;
                }
            }
            if (Math.Abs(Direction.Z) < float.Epsilon)
            {
                // Ray is parallel to slab.  No hit if origin (p in book) not within slab
                if (Origin.Z < min_Z || Origin.Z > max_Z)
                {
                    return false;
                }
            }
            else
            {
                // Compute intersection t value of ray with near and far plane of slab
                ood = 1.0f / Direction.Z;
                t1 = (min_Z - Origin.Z) * ood;
                t2 = (max_Z - Origin.Z) * ood;
 
                // Make (t1) be intersection with near plane, (t2) with far plane
                if (t1 > t2)
                {
                    Swap(ref t1, ref t2);
                }
 
                // Compute the intersection of slab intersection intervals
                t_Min = Math.Max(t_Min, t1);
                t_Max = Math.Min(t_Max, t2);
 
                // Exit with no collision as soon as slab intersection becomes empty
                if (t_Min > t_Max)
                {
                    return false;
                }
            }
 
            return true;

                                  
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:

Select allOpen in new window

This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2009-10-31 at 16:34:29ID24861275
Tags

Ray OBB Intersection 3D

Topics

3D Game Programming

,

Physics & Artificial Intelligence in Game Programming

,

Algorithms

Participating Experts
1
Points
500
Comments
38

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. Geometry intersection routines
    Does anyone have any general routines that will intersect a line in 3D space with a plane in 3D space. The line is defined by 2 points and the plane by 3 points. In addition I would like to know if the the instersection point lies within the triangle created by the 3 points o...
  2. Bezier Intersection
    Hi, Does any one know an algorithm to find the intersection of a line/ray with a 2D Bezier curve? I think it might come down to an iterative process but not sure. Any ideas/urls/algorithms greatly apprieciated. The problem has been solved here: http://www.eml.hiroshima-u....
  3. Intersects?
    I am using mysql with PHP and I want to do the following: select timetable_id from timetable where location_id = '.location_id.' intersect select timetable_id from timetable where start_date between '.$startdate.' and '.$enddate.' or end_date between '.$startdate.' and '...
  4. How do I convert a pick ray's intersection into a 3D World…
    I presume that everybody is quite familiar with picking rays, generated from a x,y point from a mouse coordinate. Take a look at the DX9SDK, and check out the Pick sample. For an even better example, take a look at : http://www.mvps.org/directx/articles/improved_ray_picking.h...

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: ikeworkPosted on 2009-11-01 at 04:44:59ID: 25713531

Hi Dr_Spankenstein,

You have to transform the ray with the inverse transformation matrix of the obb, in order to trasform the ray into obb-space. Can you show the declaration of your Obb?

ike

 

by: Dr_SpankensteinPosted on 2009-11-01 at 05:25:10ID: 25713628

Certainly can ike.  I've attached the important bits of the OBB class so you know what each parameter is.

    public class CD_OrientedBoundingBox
    {
        Vector3 Centre;                                     // OBB centre point
        Quaternion Orientation = Quaternion.Identity;       // Orientation of OBB (Rotation matrix is derived from this)
        Matrix Rotation;                                    // Local space rotation matrix (What angle the box is at)
        Vector3 Extents;                                    // Positive halfwidth extents of the OBB along each axis
        
        // To save memory you can store two Vector3 of the rotation axes
        // Compute the 3rd using Vector3.Cross at collision test time (A 3x3 matrix can then be created from these 3 Vector3's)
        
        public CD_OrientedBoundingBox(Vector3 centre, float width, float height, float depth, float yaw, float pitch, float roll)
        {
            Quaternion additionalRot = Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll);
            Orientation *= additionalRot;
            Rotation = Matrix.CreateFromQuaternion(Orientation);
 
            Centre = centre;
            Extents = new Vector3(width * 0.5f, height * 0.5f, depth * 0.5f);
        }
 
        public CD_OrientedBoundingBox(Vector3 centre, float width, float height, float depth, Matrix rotation)
        {
            Quaternion additionalRot = Quaternion.CreateFromRotationMatrix(rotation);
            Orientation *= additionalRot;
            Rotation = Matrix.CreateFromQuaternion(additionalRot);
 
            Centre = centre;
            Extents = new Vector3(width * 0.5f, height * 0.5f, depth * 0.5f);
        }
 
        // Extents (Local Space - For drawing correctly with rotation)
        public Vector3 Extents_HalfWidth
        {
            get { return Extents; }
        }
 
        /// <summary>
        /// AABB min point contained within AABB (World Space) [Transformed Extents to World Space via World Transform/Transform_World]
        /// </summary>
        public Vector3 MinPoint
        {
            get { return Vector3.Transform(-Extents, Transform_World); }  
        }
 
        /// <summary>
        /// AABB max point contained within AABB (World Space) [Transformed Extents to World Space via World Transform/Transform_World]
        /// </summary>
        public Vector3 MaxPoint
        {
            get { return Vector3.Transform(Extents, Transform_World); }  
        }
 
        public Vector3 Position
        {
            get { return Centre; }
            set { Centre = value; }
        }
 
        public Matrix Rotation_Matrix
        {
            get { return Rotation; }
        }
 
        public Vector3 Axis_X   // X axis rotation
        {
            get { return new Vector3(Rotation.M11, Rotation.M12, Rotation.M13); }
        }
 
        public Vector3 Axis_Y   // Y axis rotation
        {
            get { return new Vector3(Rotation.M21, Rotation.M22, Rotation.M23); }
        }
 
        public Vector3 Axis_Z   // Z axis rotation
        {
            get { return new Vector3(Rotation.M31, Rotation.M32, Rotation.M33); }
        }
 
        /// <summary>
        /// Used for converting body (OBB) space into world space (and vice versa) [Derived from rotation, centre]
        /// </summary>
        public Matrix Transform_World
        {
            get 
            {
                Matrix matrix_World = Rotation;
                matrix_World.Translation = Centre;
                return matrix_World;   
            }
        }

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:

Select allOpen in new window

 

by: ikeworkPosted on 2009-11-01 at 05:48:40ID: 25713685

Ok, to transform the ray, you can just take either

1) the conjugated quaternion CD_OrientedBoundingBox::Orientation (which is the inverse quaternion for unit quats) or
2) use the inverted rotation matrix CD_OrientedBoundingBox::Rotation

for both you must scale the result with CD_OrientedBoundingBox::Extents and apply the centre.

It would e easier if you store everything in a 4x4-matrix (Centre, Extents and Rotation), but its not necessary to acheive what you want, however it would be cleaner.

Btw, your variable names are weird here (Orientation and Rotation). Both, the matrix and the quaternion are orientations, stored in a quaternion and in a matrix.


ike

 

by: Dr_SpankensteinPosted on 2009-11-01 at 06:19:37ID: 25713753

Couple of questions:

Can I use the transpose (for speed) instead of the inverse of the rotation matrix as they are both the same result?

As my test against the 3 slabs are all based on min and max points am I creating the projected ray correctly?

Vector3 min_Local = Vector3.Transform(Origin, orientation_Inverse)
AND
Vector3 max_Local = Vector3.Transform(Origin, orientation_Inverse)

and something similar to this:

            // Translate ray to OBB space
            Vector3 min_Local = Vector3.Transform(Origin, orientation_Inverse) * oBB.MinPoint;
            Vector3 max_Local = Vector3.Transform(Origin, orientation_Inverse) * oBB.MaxPoint;

            float min_X = Vector3.Dot(min_Local, oBB.Axis_X);
            float max_X = Vector3.Dot(max_Local, oBB.Axis_X);
            float min_Y = Vector3.Dot(min_Local, oBB.Axis_Y);
            float max_Y = Vector3.Dot(max_Local, oBB.Axis_Y);
            float min_Z = Vector3.Dot(min_Local, oBB.Axis_Z);
            float max_Z = Vector3.Dot(max_Local, oBB.Axis_Z);

Or have I got the wrong end of the stick?

 

by: ikeworkPosted on 2009-11-01 at 06:36:41ID: 25713800

>> Can I use the transpose (for speed) instead of the inverse of the rotation matrix

Yes, if it is only a 3x3 orientation matrix, then the transpose is the inverse

>> As my test against the 3 slabs are all based on min and max points am I creating the projected ray correctly?

You must transform the ray in the obb's space, not the other way around. In Obb-space the obb is an Aabb, so you can easily test against the values in "Extents". No need to calculate world-points of obb's min & max.

Can you show, how your ray is defined? All you need to do is multiply the ray's member with the inverse transform-matrix of the obb. That is including Center, Extents and Orientation in a 4x4-matrix as said above.

 

by: Dr_SpankensteinPosted on 2009-11-01 at 06:55:14ID: 25713846

My ray is defined as follows:

The ray has an origin and a direction (non normalized).

    public class CD_Ray
    {
        public Vector3 Origin;
        public Vector3 Direction;
 
        public CD_Ray(Vector3 origin, Vector3 direction)
        {
            // Some collision detections method might not work with a normalised direction vector
            // Therefore direction is not normalised
            Origin = origin;
            Direction = direction;
        }

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:

Select allOpen in new window

 

by: ikeworkPosted on 2009-11-01 at 07:34:19ID: 25714004

Here is how you can create the 4x4 matrix and its inverse for the obb:

class Obb
{
public:
    Obb(const vector &center, const quaternion &orientation, const vector &extents)
    {
        m_transform = matrix::translate(center) * matrix::from_quaternion(orientation) * matrix::scale(extents[0], extents[1], extents[2]);
        m_transformInv = matrix::scale(1.0f/extents[0], 1.0f/extents[1], 1.0f/extents[2]) * matrix::from_quaternion(quaternion::conjugate(orientation)) * matrix::translate(-center);
    }
 
private:
    matrix m_transform;
    matrix m_transformInv;
};

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:

Select allOpen in new window

 

by: ikeworkPosted on 2009-11-01 at 07:43:43ID: 25714035

ok, then just multiply CD_Ray::Origin and CD_Ray::Direction with Obb::m_transformInv, then the ray is in obb space, and you can make a Aabb/Ray test, which is much easier

 

by: Dr_SpankensteinPosted on 2009-11-01 at 08:06:37ID: 25714145

Fantastic, thank you!  I kept the same test as an AABB and added the following:

            // Transform the ray into OBB space
            Matrix orientation_Inverse = Matrix.Transpose(oBB.Rotation_Matrix);
            Vector3 origin_Projected = Vector3.Transform(Origin, orientation_Inverse);
            Vector3 direction_Projected = Vector3.Transform(Direction, orientation_Inverse);

One final question, how do I now obtain the correct normal from the intersection point?

I have attached how I do it with an AABB but I am not sure how to take the orientation into account.

        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) * Vector3.UnitX;    // Cardinal axis for X
            }
            distance = Math.Abs(Extents.Y - Math.Abs(point.Y));
            if (distance < min)
            {
                min = distance;
                normal = Math.Sign(point.Y) * Vector3.UnitY;    // Cardinal axis for Y
            }
            distance = Math.Abs(Extents.Z - Math.Abs(point.Z));
            if (distance < min)
            {
                min = distance;
                normal = Math.Sign(point.Z) * Vector3.UnitZ;    // Cardinal axis for Z
            }
 
            return normal;
        }

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:

Select allOpen in new window

 

by: ikeworkPosted on 2009-11-01 at 08:09:59ID: 25714158

Which normal fo you mean? There is no normal, only the rays direction, do you mean that?

 

by: ikeworkPosted on 2009-11-01 at 08:12:24ID: 25714170

>> Fantastic, thank you!  I kept the same test as an AABB and added the following:
>> 
>>             // Transform the ray into OBB space
>>             Matrix orientation_Inverse = Matrix.Transpose(oBB.Rotation_Matrix);
>>             Vector3 origin_Projected = Vector3.Transform(Origin, orientation_Inverse);
>>             Vector3 direction_Projected = Vector3.Transform(Direction, orientation_Inverse);

You didnt read my post properly. You need to transform the ray not only by the inverse of the Orientation, look in my example, how you get the entire inverse transform of the obb, you have to use the extent and center too, like in my example

 

by: Dr_SpankensteinPosted on 2009-11-01 at 08:47:32ID: 25714298

Transforming the ray by the inverse of the Orientation works perfectly though?!  Do you want me to multiply the transformed ray by the extents, I don't follow, sorry.

By normal I mean the surface normal of the OBB face that the ray is intersecting with.  The intersection point is a point on the OBB and the normal is the surface normal of the face of the OBB.

 

by: ikeworkPosted on 2009-11-01 at 08:48:55ID: 25714306

I try to explain it better. The complete 4x4 transform matrix (Center, Orientation, Extent) of an Obb can be created like this:

Mt -> translate to center matrix
Mo -> orientation matrix
Me -> scale-matrix with extents

M = Mt * Mo * Me

the inverse is:

MInv = MeInv * MoInv * MtInv

Note, that the multiplication order here is for matrices with column-major form (OpenGL). DirectX would be the other way around

Nor the members of your ray must be multiplicated with MInv, then it is transformed in Obb's space, and you can make an Aabb-Ray intersection test

 

by: ikeworkPosted on 2009-11-01 at 08:52:50ID: 25714319

>> Transforming the ray by the inverse of the Orientation works perfectly though?!

It will only work, if the center of the Obb is at {0, 0, 0} and has an extent of {1, 1, 1}
But maybe I missed something. Can you show your Obb-Ray-Intersectiontest function please?

 

by: Dr_SpankensteinPosted on 2009-11-01 at 10:43:29ID: 25714814

Sure thing, the entire code for a ray/OBB intersection test is as follows:

        private bool IntersectOBB(CD_OrientedBoundingBox oBB, ref Contact contact)
        {
            float t_Min = 0.0f;
 
            // Maximum distance ray can travel (makes it a segment, otherwise it would be infinite)
            float t_Max = float.MaxValue;
 
            float ood = 0.0f;
            float t1 = 0.0f;
            float t2 = 0.0f;
 
            // Transform the ray into OBB space
            Matrix orientation_Inverse = Matrix.Transpose(oBB.Rotation_Matrix);
            Vector3 origin_Projected = Vector3.Transform(Origin, orientation_Inverse);
            Vector3 direction_Projected = Vector3.Transform(Direction, orientation_Inverse);
 
            // For all 3 slabs
            if (Math.Abs(Direction.X) < float.Epsilon)
            {
                // Ray is parallel to slab.  No hit if origin (p in book) not within slab
                if (Origin.X < oBB.MinPoint.X || Origin.X > oBB.MaxPoint.X)
                {
                    return false;
                }
            }
            else
            {
                // Compute intersection t value of ray with near and far plane of slab
                ood = 1.0f / Direction.X;
                t1 = (oBB.MinPoint.X - Origin.X) * ood;
                t2 = (oBB.MaxPoint.X - Origin.X) * ood;
 
                // Make (t1) be intersection with near plane, (t2) with far plane
                if (t1 > t2)
                {
                    Swap(ref t1, ref t2);
                }
 
                // Compute the intersection of slab intersection intervals
                t_Min = Math.Max(t_Min, t1);
                t_Max = Math.Min(t_Max, t2);
 
                // Exit with no collision as soon as slab intersection becomes empty
                if (t_Min > t_Max)
                {
                    return false;
                }
            }
            if (Math.Abs(Direction.Y) < float.Epsilon)
            {
                // Ray is parallel to slab.  No hit if origin (p in book) not within slab
                if (Origin.Y < oBB.MinPoint.Y || Origin.Y > oBB.MaxPoint.Y)
                {
                    return false;
                }
            }
            else
            {
                // Compute intersection t value of ray with near and far plane of slab
                ood = 1.0f / Direction.Y;
                t1 = (oBB.MinPoint.Y - Origin.Y) * ood;
                t2 = (oBB.MaxPoint.Y - Origin.Y) * ood;
 
                // Make (t1) be intersection with near plane, (t2) with far plane
                if (t1 > t2)
                {
                    Swap(ref t1, ref t2);
                }
 
                // Compute the intersection of slab intersection intervals
                t_Min = Math.Max(t_Min, t1);
                t_Max = Math.Min(t_Max, t2);
 
                // Exit with no collision as soon as slab intersection becomes empty
                if (t_Min > t_Max)
                {
                    return false;
                }
            }
            if (Math.Abs(Direction.Z) < float.Epsilon)
            {
                // Ray is parallel to slab.  No hit if origin (p in book) not within slab
                if (Origin.Z < oBB.MinPoint.Z || Origin.Z > oBB.MaxPoint.Z)
                {
                    return false;
                }
            }
            else
            {
                // Compute intersection t value of ray with near and far plane of slab
                ood = 1.0f / Direction.Z;
                t1 = (oBB.MinPoint.Z - Origin.Z) * ood;
                t2 = (oBB.MaxPoint.Z - Origin.Z) * ood;
 
                // Make (t1) be intersection with near plane, (t2) with far plane
                if (t1 > t2)
                {
                    Swap(ref t1, ref t2);
                }
 
                // Compute the intersection of slab intersection intervals
                t_Min = Math.Max(t_Min, t1);
                t_Max = Math.Min(t_Max, t2);
 
                // Exit with no collision as soon as slab intersection becomes empty
                if (t_Min > t_Max)
                {
                    return false;
                }
            }
 
            // Ray intersects all 3 slabs
            // Only update contact parameters if this is the closest intersected so far
            if (contact.KeepClosest(t_Min))
            {
                contact.location = Origin + t_Min * Direction;
                contact.normal = contact.location - oBB.Position;
 
                // Only allow this test to return true if the primitive tested is the closest to the ray origin
                return true;
            }
 
            return false;
        }

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:

Select allOpen in new window

 

by: ikeworkPosted on 2009-11-01 at 14:09:15ID: 25715819

You dont use the center and the extents of the obb in that function to transform the ray into Obb-space. You're sure the function works as it is?

 

by: ikeworkPosted on 2009-11-01 at 14:13:31ID: 25715840

>> Transforming the ray by the inverse of the Orientation works perfectly though?!

You dont even use origin_Projected and direction_Projected. Did you copy this function from somewhere, it would be good to have the original function, to see where it went wrong.
Otherwise it would be better to start from scratch, than to use something that doesnt work at all.

 

by: Dr_SpankensteinPosted on 2009-11-01 at 14:35:52ID: 25715936

Ah, sorry you are correct.  The original function is what I have posted.  It is a test for a ray against an AABB.  

It worked as it was treating the OBB as an AABB so I could use the code if I can correctly transform the ray into the OBB space, correct?

If I understand you correctly you want me to transform the ray into OBB space by using the inverse world transform matrix (scale, rotate, translate for directX)?

This way I end up with what is attached:

This works as it should but I still can't figure out the surface normal?

The world transfom is a follows (the scale does not need to be included as the extents take care of that):

        /// <summary>
        /// Used for converting body (OBB) space into world space (and vice versa) [Derived from rotation, centre]
        /// </summary>
        public Matrix Transform_World
        {
            get
            {
                Matrix matrix_World = Rotation;
                matrix_World.Translation = Centre;
                return matrix_World;  
            }
        }

        private bool IntersectOBB(CD_OrientedBoundingBox oBB, ref Contact contact)
        {
            float t_Min = 0.0f;
 
            // Maximum distance ray can travel (makes it a segment, otherwise it would be infinite)
            float t_Max = float.MaxValue;
 
            float ood = 0.0f;
            float t1 = 0.0f;
            float t2 = 0.0f;
 
            // Transform the ray into OBB space
            Matrix world_Inverse = Matrix.Invert(oBB.Transform_World);
            Vector3 origin_Projected = Vector3.Transform(Origin, world_Inverse);
            Vector3 direction_Projected = Vector3.Transform(Direction, world_Inverse);
 
            // For all 3 slabs
            if (Math.Abs(direction_Projected.X) < float.Epsilon)
            {
                // Ray is parallel to slab.  No hit if origin (p in book) not within slab
                if (origin_Projected.X < oBB.MinPoint.X || origin_Projected.X > oBB.MaxPoint.X)
                {
                    return false;
                }
            }
            else
            {
                // Compute intersection t value of ray with near and far plane of slab
                ood = 1.0f / direction_Projected.X;
                t1 = (oBB.MinPoint.X - origin_Projected.X) * ood;
                t2 = (oBB.MaxPoint.X - origin_Projected.X) * ood;
 
                // Make (t1) be intersection with near plane, (t2) with far plane
                if (t1 > t2)
                {
                    Swap(ref t1, ref t2);
                }
 
                // Compute the intersection of slab intersection intervals
                t_Min = Math.Max(t_Min, t1);
                t_Max = Math.Min(t_Max, t2);
 
                // Exit with no collision as soon as slab intersection becomes empty
                if (t_Min > t_Max)
                {
                    return false;
                }
            }
            if (Math.Abs(direction_Projected.Y) < float.Epsilon)
            {
                // Ray is parallel to slab.  No hit if origin (p in book) not within slab
                if (origin_Projected.Y < oBB.MinPoint.Y || origin_Projected.Y > oBB.MaxPoint.Y)
                {
                    return false;
                }
            }
            else
            {
                // Compute intersection t value of ray with near and far plane of slab
                ood = 1.0f / direction_Projected.Y;
                t1 = (oBB.MinPoint.Y - origin_Projected.Y) * ood;
                t2 = (oBB.MaxPoint.Y - origin_Projected.Y) * ood;
 
                // Make (t1) be intersection with near plane, (t2) with far plane
                if (t1 > t2)
                {
                    Swap(ref t1, ref t2);
                }
 
                // Compute the intersection of slab intersection intervals
                t_Min = Math.Max(t_Min, t1);
                t_Max = Math.Min(t_Max, t2);
 
                // Exit with no collision as soon as slab intersection becomes empty
                if (t_Min > t_Max)
                {
                    return false;
                }
            }
            if (Math.Abs(direction_Projected.Z) < float.Epsilon)
            {
                // Ray is parallel to slab.  No hit if origin (p in book) not within slab
                if (origin_Projected.Z < oBB.MinPoint.Z || origin_Projected.Z > oBB.MaxPoint.Z)
                {
                    return false;
                }
            }
            else
            {
                // Compute intersection t value of ray with near and far plane of slab
                ood = 1.0f / direction_Projected.Z;
                t1 = (oBB.MinPoint.Z - origin_Projected.Z) * ood;
                t2 = (oBB.MaxPoint.Z - origin_Projected.Z) * ood;
 
                // Make (t1) be intersection with near plane, (t2) with far plane
                if (t1 > t2)
                {
                    Swap(ref t1, ref t2);
                }
 
                // Compute the intersection of slab intersection intervals
                t_Min = Math.Max(t_Min, t1);
                t_Max = Math.Min(t_Max, t2);
 
                // Exit with no collision as soon as slab intersection becomes empty
                if (t_Min > t_Max)
                {
                    return false;
                }
            }
 
            // Ray intersects all 3 slabs
            // Only update contact parameters if this is the closest intersected so far
            if (contact.KeepClosest(t_Min))
            {
                contact.location = Origin + t_Min * direction_Projected;
                contact.normal = contact.location - oBB.Position;
 
                // Only allow this test to return true if the primitive tested is the closest to the ray origin
                return true;
            }
 
            return false;
        }

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:

Select allOpen in new window

 

by: ikeworkPosted on 2009-11-01 at 15:20:38ID: 25716145

What is your question? You need to explain more about the code you showed. Is it working? What is not working?
Where do you have the code from, so I can have a look at the original, to see where you come from. Its hard, to help you without that information.

 

by: Dr_SpankensteinPosted on 2009-11-01 at 15:29:33ID: 25716180

Sorry, bear with me here.

I've attached the original test between a ray and an AABB, the ray/OBB is derived from this.

The surface normal is obtained using the following:

        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) * Vector3.UnitX;    // Cardinal axis for X
            }
            distance = Math.Abs(Extents.Y - Math.Abs(point.Y));
            if (distance < min)
            {
                min = distance;
                normal = Math.Sign(point.Y) * Vector3.UnitY;    // Cardinal axis for Y
            }
            distance = Math.Abs(Extents.Z - Math.Abs(point.Z));
            if (distance < min)
            {
                min = distance;
                normal = Math.Sign(point.Z) * Vector3.UnitZ;    // Cardinal axis for Z
            }

            return normal;
        }

How do I change the normal finding function to accomodate the orientation of the OBB?

        private bool IntersectAABB(CD_AxisAlignedBoundingBox aABB, ref Contact contact)
        {
            float t_Min = 0.0f;
 
            // Maximum distance ray can travel (makes it a segment, otherwise it would be infinite)
            float t_Max = float.MaxValue;   
            
            float ood = 0.0f;
            float t1 = 0.0f;
            float t2 = 0.0f;
 
            // For all 3 slabs
            if (Math.Abs(Direction.X) < float.Epsilon)
            {
                // Ray is parallel to slab.  No hit if origin (p in book) not within slab
                if (Origin.X < aABB.MinPoint.X || Origin.X > aABB.MaxPoint.X)
                {
                    return false;
                }
            }
            else
            {
                // Compute intersection t value of ray with near and far plane of slab
                ood = 1.0f / Direction.X;
                t1 = (aABB.MinPoint.X - Origin.X) * ood;
                t2 = (aABB.MaxPoint.X - Origin.X) * ood;
 
                // Make (t1) be intersection with near plane, (t2) with far plane
                if (t1 > t2)
                {
                    Swap(ref t1, ref t2);
                }
 
                // Compute the intersection of slab intersection intervals
                t_Min = Math.Max(t_Min, t1);
                t_Max = Math.Min(t_Max, t2);
 
                // Exit with no collision as soon as slab intersection becomes empty
                if (t_Min > t_Max)
                {
                    return false;
                }
            }
            if (Math.Abs(Direction.Y) < float.Epsilon)
            {
                // Ray is parallel to slab.  No hit if origin (p in book) not within slab
                if (Origin.Y < aABB.MinPoint.Y || Origin.Y > aABB.MaxPoint.Y)
                {
                    return false;
                }
            }
            else
            {
                // Compute intersection t value of ray with near and far plane of slab
                ood = 1.0f / Direction.Y;
                t1 = (aABB.MinPoint.Y - Origin.Y) * ood;
                t2 = (aABB.MaxPoint.Y - Origin.Y) * ood;
 
                // Make (t1) be intersection with near plane, (t2) with far plane
                if (t1 > t2)
                {
                    Swap(ref t1, ref t2);
                }
 
                // Compute the intersection of slab intersection intervals
                t_Min = Math.Max(t_Min, t1);
                t_Max = Math.Min(t_Max, t2);
 
                // Exit with no collision as soon as slab intersection becomes empty
                if (t_Min > t_Max)
                {
                    return false;
                }
            }
            if (Math.Abs(Direction.Z) < float.Epsilon)
            {
                // Ray is parallel to slab.  No hit if origin (p in book) not within slab
                if (Origin.Z < aABB.MinPoint.Z || Origin.Z > aABB.MaxPoint.Z)
                {
                    return false;
                }
            }
            else
            {
                // Compute intersection t value of ray with near and far plane of slab
                ood = 1.0f / Direction.Z;
                t1 = (aABB.MinPoint.Z - Origin.Z) * ood;
                t2 = (aABB.MaxPoint.Z - Origin.Z) * ood;
 
                // Make (t1) be intersection with near plane, (t2) with far plane
                if (t1 > t2)
                {
                    Swap(ref t1, ref t2);
                }
 
                // Compute the intersection of slab intersection intervals
                t_Min = Math.Max(t_Min, t1);
                t_Max = Math.Min(t_Max, t2);
 
                // Exit with no collision as soon as slab intersection becomes empty
                if (t_Min > t_Max)
                {
                    return false;
                }
            }
 
            // Ray intersects all 3 slabs
            // Only update contact parameters if this is the closest intersected so far
            if (contact.KeepClosest(t_Min))
            {
                contact.location = Origin + t_Min * Direction;
                contact.normal = aABB.GetNormalFromPoint(contact.location);
 
                // Only allow this test to return true if the primitive tested is the closest to the ray origin
                return true;
            }
              
            return false;
        }

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:

Select allOpen in new window

 

by: ikeworkPosted on 2009-11-01 at 15:32:01ID: 25716188

Without that information i can just repeat myself, the general way is to transform the ray into the obb-space, which is shown above.
When you did that, you can make an Aabb/Ray test.

 

by: ikeworkPosted on 2009-11-01 at 15:39:40ID: 25716206

Ok, your question was: "Ray OBB intersection not working.  Ray not transformed into OBB space correctly?"

I showed you how to transform the ray into Obb-space. If that did not help you, I'm not sure what your actual question is and how I can help you.

 

by: Dr_SpankensteinPosted on 2009-11-01 at 15:43:07ID: 25716221

Then I can't have transformed the ray correctly into OBB space.  What is wrong with the following?

            // Transform the ray into OBB space
            Matrix world_Inverse = Matrix.Invert(oBB.Transform_World);
            Vector3 origin_Projected = Vector3.Transform(Origin, world_Inverse);
            Vector3 direction_Projected = Vector3.Transform(Direction, world_Inverse);

I thought I had followed what you suggested?

OBB Transform :  

 public Matrix Transform_World
        {
            get
            {
                Matrix matrix_World = Rotation;
                matrix_World.Translation = Centre;
                return matrix_World;  
            }
        }

 

by: Dr_SpankensteinPosted on 2009-11-01 at 15:56:04ID: 25716266

So you are saying that I have transormed the ray correctly?

 

by: ikeworkPosted on 2009-11-02 at 03:24:15ID: 25718480

>> So you are saying that I have transormed the ray correctly?

Yes, it looks good so far. Now you must be careful, what Obb-points you use in the function. You must only use the obb-space-points (Extents), not the obb-world points.

 

by: Dr_SpankensteinPosted on 2009-11-03 at 08:44:46ID: 25730816

I have followed everything you have said correctly and the test does not work. :(

Can you see what might be wrong with the following steps:

1) Transform the ray

            // Transform the ray from world space into OBB space
            Matrix world_Inverse = Matrix.Invert(oBB.Transform_World);
            Vector3 origin_Projected = Vector3.Transform(Origin, world_Inverse);
            Vector3 direction_Projected = Vector3.Transform(Direction, world_Inverse);
            direction_Projected.Normalize();

2) Use the OBB space points

            // Min/Max point in OBB space
            Vector3 oBB_Max = oBB.Centre + oBB.Extents;
            Vector3 oBB_Min = oBB.Centre - oBB.Extents;

3) Do working AABB intersection test

 

by: ikeworkPosted on 2009-11-03 at 09:08:27ID: 25731088

You  must not use oBB.Centre in (2)
Because you are now in Obb-space. For the Obb, its Centre is at {0, 0, 0}

 

by: Dr_SpankensteinPosted on 2009-11-03 at 13:24:30ID: 25733889

I've tried that aswell but it doesn't work either?

 

by: ikeworkPosted on 2009-11-03 at 22:46:09ID: 25736981

Please post the current code

 

by: Dr_SpankensteinPosted on 2009-11-04 at 03:34:05ID: 25738260

Absolutely, thanks for sticking with me on this problem.

Please find the code attached:

        private bool IntersectOBB(CD_OrientedBoundingBox oBB, ref Contact contact)
        {
            //Matrix rotation_Inverse = Matrix.Transpose(oBB.Orientation_Matrix);
         
            //Vector3 origin_Projected = Vector3.Transform((Origin - oBB.Centre), rotation_Inverse);
            //Vector3 direction_Projected = origin_Projected + Vector3.Transform(Direction, rotation_Inverse);
 
            // P - C.u0 method
            //Vector3 origin_Projected = Vector3.Zero;
            //origin_Projected.X = Vector3.Dot(Origin - oBB.Centre, oBB.Axis_X);
            //origin_Projected.Y = Vector3.Dot(Origin - oBB.Centre, oBB.Axis_Y);
            //origin_Projected.Z = Vector3.Dot(Origin - oBB.Centre, oBB.Axis_Z);
 
            //Vector3 direction_Projected = Vector3.Zero;
            //origin_Projected.X = origin_Projected.X + Vector3.Dot(Direction, oBB.Axis_X);
            //origin_Projected.Y = origin_Projected.Y + Vector3.Dot(Direction, oBB.Axis_Y);
            //origin_Projected.Z = origin_Projected.Z + Vector3.Dot(Direction, oBB.Axis_Z);
 
            // Transform the ray from world space into OBB space
            Matrix world_Inverse = Matrix.Invert(oBB.Transform_World);
            Vector3 origin_Projected = Vector3.Transform(Origin, world_Inverse);
            Vector3 direction_Projected = Vector3.Transform(Direction, world_Inverse);
            direction_Projected.Normalize();
 
            // Min/Max point in OBB space
            Vector3 oBB_Max = oBB.Extents;
            Vector3 oBB_Min = -oBB.Extents;
            
            float t_Min = 0.0f;
 
            // Maximum distance ray can travel (makes it a segment, otherwise it would be infinite)
            float t_Max = float.MaxValue;
 
            float ood = 0.0f;
            float t1 = 0.0f;
            float t2 = 0.0f;
 
            // For all 3 slabs (x, y, z) [A slab is the space between a pair of parallel planes]
            for (int i = 0; i < 3; i++)
            {
                if (Math.Abs(Vector3Index.Get(ref direction_Projected, i)) < float.Epsilon)
                {
                    // Ray is parallel to slab.  No hit if origin (p in book) not within slab
                    if (Vector3Index.Get(ref origin_Projected, i) < Vector3Index.Get(ref oBB_Min, i) || Vector3Index.Get(ref origin_Projected, i) > Vector3Index.Get(ref oBB_Max, i))
                    {
                        return false;
                    }
                }
                else
                {
                    // Compute intersection t value of ray with near and far plane of slab
                    ood = 1.0f / Vector3Index.Get(ref direction_Projected, i);
                    t1 = (Vector3Index.Get(ref oBB_Min, i) - Vector3Index.Get(ref origin_Projected, i)) * ood;
                    t2 = (Vector3Index.Get(ref oBB_Max, i) - Vector3Index.Get(ref origin_Projected, i)) * ood;
 
                    // Make (t1) be intersection with near plane, (t2) with far plane
                    if (t1 > t2)
                    {
                        Swap(ref t1, ref t2);
                    }
 
                    // Compute the intersection of slab intersection intervals
                    t_Min = Math.Max(t_Min, t1);
                    t_Max = Math.Min(t_Max, t2);
 
                    // Exit with no collision as soon as slab intersection becomes empty
                    if (t_Min > t_Max)
                    {
                        return false;
                    }
                }
            }
 
            // Ray intersects all 3 slabs
            // Only update contact parameters if this is the closest intersected so far
            if (contact.KeepClosest(t_Min))
            {
                contact.location = origin_Projected + t_Min * direction_Projected;
                //contact.normal = aABB.GetNormalFromPoint(contact.location);
 
                // Only allow this test to return true if the primitive tested is the closest to the ray origin
                return true;
            }
 
            return false;
        }

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:

Select allOpen in new window

 

by: Dr_SpankensteinPosted on 2009-11-04 at 03:35:10ID: 25738269

I will also attach the code for an OBB below so that you can see how the Extents are created:

Thanks.

        public CD_OrientedBoundingBox(Vector3 centre, float width, float height, float depth, Matrix rotation)
        {
            Quaternion additionalRot = Quaternion.CreateFromRotationMatrix(rotation);
            Orientation *= additionalRot;
            Rotation = Matrix.CreateFromQuaternion(additionalRot);
 
            Centre = centre;
            Extents = new Vector3(width * 0.5f, height * 0.5f, depth * 0.5f);
        }
 
        /// <summary>
        /// AABB min point contained within AABB (World Space) [Transformed Extents to World Space via World Transform/Transform_World]
        /// </summary>
        public Vector3 MinPoint
        {
            get { return Vector3.Transform(-Extents, Transform_World); }  
        }
 
        /// <summary>
        /// AABB max point contained within AABB (World Space) [Transformed Extents to World Space via World Transform/Transform_World]
        /// </summary>
        public Vector3 MaxPoint
        {
            get { return Vector3.Transform(Extents, Transform_World); }  
        }
 
        public Vector3 Position
        {
            get { return Centre; }
            set { Centre = value; }
        }
 
        public Matrix Orientation_Matrix
        {
            get { return Rotation; }
        }
 
        public Quaternion Orientation_Quaternion
        {
            get { return Orientation; }
        }
 
        /// <summary>
        /// Used for converting body (OBB) space into world space (and vice versa) [Derived from rotation, centre]
        /// </summary>
        public Matrix Transform_World
        {
            get 
            {
                Matrix matrix_World = Rotation;
                matrix_World.Translation = Centre;
                return matrix_World;   
            }
        }

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:

Select allOpen in new window

 

by: ikeworkPosted on 2009-11-04 at 04:48:45ID: 25738728

Why do you multiply

  Orientation *= additionalRot;

in constructor of CD_OrientedBoundingBox? Is Orientation initialized with any value?

Now I would test each thing seperately.
- Render the Obb and check if the values work
- Test your function with an obb without any rotation (like an Aabb)
- Test your functions and see where they are wrong
- render both the obb/aabb and the ray

 

by: ikeworkPosted on 2009-11-04 at 04:49:46ID: 25738736

Btw. MinPoint & MinPoint make no sense as members of an Obb, you can only be sure for an Aabb that MinPoint = -Extents

 

by: Dr_SpankensteinPosted on 2009-11-04 at 05:48:41ID: 25739219

Orientation is initially set to the following:

Quaternion Orientation = Quaternion.Identity;       // Orientation of OBB (Rotation matrix is derived from this)

The OBB works well and renders fine (I am already rendering as a wireframe, along with the ray).  

OBB/ABBB collision detection works correctly
OBB/OBB collision detection works correctly
OBB/Plane collision detection works correctly
OBB/Triangle collision detection works correctly
OBB/Sphere collision detection works correctly

Ray/OBB is the only OBB related method that doesn't work.

Testing my function without rotation (Matrix.Indentity) works perfectly if I don't project the ray into OBB space.  If I project the ray into OBB space then it fails.

So to clarify:

            Vector3 origin_Projected = Origin;
            Vector3 direction_Projected = Direction;

            // Min/Max point in OBB space
            Vector3 oBB_Max = oBB.MaxPoint;
            Vector3 oBB_Min = oBB.MinPoint;

Works, where:

        /// <summary>
        /// AABB min point contained within AABB (World Space) [Transformed Extents to World Space via World Transform/Transform_World]
        /// </summary>
        public Vector3 MinPoint
        {
            get { return Vector3.Transform(-Extents, Transform_World); }  
        }

        /// <summary>
        /// AABB max point contained within AABB (World Space) [Transformed Extents to World Space via World Transform/Transform_World]
        /// </summary>
        public Vector3 MaxPoint
        {
            get { return Vector3.Transform(Extents, Transform_World); }  
        }

Although -Extents is only correct for an AABB.

If I use:

            // Transform the ray from world space into OBB space
            Matrix world_Inverse = Matrix.Invert(oBB.Transform_World);
            Vector3 origin_Projected = Vector3.Transform(Origin, world_Inverse);
            Vector3 direction_Projected = Vector3.Transform(Direction, world_Inverse);
            direction_Projected.Normalize();

            // Min/Max point in OBB space
            Vector3 oBB_Max = oBB.MaxPoint;
            Vector3 oBB_Min = oBB.MinPoint;

The test fails.

So this leads me to think that the Max Point and Min Point are not being returned correctly when the OBB is rotated.

What have I done wrong there?

 

by: ikeworkPosted on 2009-11-04 at 08:42:45ID: 25741180

>> So this leads me to think that the Max Point and Min Point are not being returned correctly when the OBB is rotated.

Thats what I just told you in my previous post.

 

by: ikeworkPosted on 2009-11-04 at 08:44:34ID: 25741206

Min and Max point in Obb-space is this:

MinPoint = -Extents;
MaxPoint = Extents;

 

by: Dr_SpankensteinPosted on 2009-11-04 at 08:56:12ID: 25741328

But using that doesn't work:

            // Transform the ray from world space into OBB space
            Matrix world_Inverse = Matrix.Invert(oBB.Transform_World);
            Vector3 origin_Projected = Vector3.Transform(Origin, world_Inverse);
            Vector3 direction_Projected = Vector3.Transform(Direction, world_Inverse);
            direction_Projected.Normalize();

            // Min/Max point in OBB space
            Vector3 oBB_Max = oBB.Extents;
            Vector3 oBB_Min = -oBB.Extents;

 

by: Dr_SpankensteinPosted on 2009-11-10 at 05:50:50ID: 25785280

I've solved the problem:

Before the AABB intersection test I now have the following:

            // Inverse of 3x3 OBB matrix is used to transform ray from world space to OBB space
            Matrix rotation_Inverse = Matrix.Transpose(oBB.Orientation_Matrix);

            // Transform the ray from world space into OBB space
            // Ray's Origin and OBB are translated to the origin
            Vector3 origin_Projected = Vector3.Transform(Origin - oBB.Centre, rotation_Inverse);
            Vector3 direction_Projected = Vector3.Transform(Direction, rotation_Inverse);

            // Min/Max point in OBB space
            Vector3 oBB_Max = oBB.Extents;
            Vector3 oBB_Min = -oBB.Extents;

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...