Cocos2d-x tutorial (34)-3D object OBB Collision Detection Algorithm

Source: Internet
Author: User

Cocos2d-x tutorial (34)-3D object OBB Collision Detection Algorithm


Welcome to Cocos2d-x chat group: 193411763


Reprinted please indicate the original source: http://blog.csdn.net/u012945598/article/details/39665911



Certificate ----------------------------------------------------------------------------------------------------------------------------------------

In the previous article explains the AABB cylinder collision detection principle, and at the end of the article mentioned the Cocos2d-x 3.3beta0 version of Small and Medium turtle Collision Detection example, this example is not AABB collision detection, this is a more accurate collision detection method for the OBB box than the AABB box. This article will introduce the OBB box and its collision detection methods.


1. The OBB Box (Oriented Bounding Box) is also called a directed Box or a Oriented Box. It will move, scale, and rotate as the object moves. Simply put, it is an AABB box that can rotate. Developers who have used physical engines in Cocos2d-x must have seen that when we create an object in the physical world and enable debugging mode, this object will be surrounded by Red rectangles, when an object is translated or rotated, the red rectangle performs the same operation. The red rectangle is the OBB box of the object. 1-1:
Figure 1-1 compared with the AABB box, the collision precision of OBB is higher than that of AABB, but the improvement of precision also reduces the efficiency, the OBB algorithm is undoubtedly more complex than AABB, and the memory consumption is also greater. We can draw a conclusion from the OBB expression.
Expression of the obb box:
There are several ways to express an AABB box or an OBB box, but you need to select the best one. For AABB, we usually only need to use the coordinate information of two vertices to identify an AABB box. Other vertex information can be calculated. However, the expression of the OBB box is obviously insufficient because there are only two points of information.
To uniquely identify an OBB box, we probably think of using a set of eight vertices, a set of six faces, a vertex, and an edge vector of three orthogonal to each other, or a central point, a rotating matrix, and three 1/2-side-lengths (Note: A rotating matrix contains three rotating axes. If a two-dimensional OBB box is surrounded by a central point, two rotating axes, two 1/2 edges ).
The last method above is the most commonly used method. Let's take a look at the code in CCOBB. h In Cocos2d-x 3.3beta0:
Vec3 _ center; // center point/* the following three variables are orthogonal unit vectors, which define the x, y, and Z axes of the current OBB box for vector projection */Vec3 _ xAxis; // enclose the unit vector Vec3 _ yAxis in the X axis of the box; // The unit vector Vec3 _ zAxis in the Y axis of the box. // enclose the unit vector Vec3 _ extents in the Z axis of the box; // 3 1/2 sides long, half length, half width, half height

Cocos2d-x 3.0beta0 defines five member variables in CCOBB. h. Each data type is a three-dimensional vector that contains three floating point numbers. That is to say, to express an OBB box, 15 float variables are required, occupying 60 bytes. However, it indicates that an AABB box requires only two vertices and 24 bytes, in this regard, the memory consumption of OBB is very high.

One way to reduce overhead is to store only the two axes of the rotating matrix, but to calculate the third axis by using the cross product during testing. This can reduce CPU overhead and save three floating point components, reduce memory consumption by 20%.


Creating an OBB box: it is very complicated to use an efficient algorithm to construct a closely enclosed OBB box or an AABB box, because the shapes of objects surrounded by different shapes are different, here we do not discuss the construction of OBB surrounded box principle, just understand the Cocos2d-x 3.3beta0 for us to provide the construction method. Two methods are used in the Cocos2d-x to calculate the OBB. The first method is a simplified OBB construction algorithm, and an AABB box is used to determine the final OBB box, another method is to use the covariance matrix to determine a direction box (in fact, whether it is an AABB box or an OBB box, the real difficulty lies in the construction of the box ).
The first method in Cocos2d-x is easier to use, for example:
AABB aabb = _ sprite-> getAABB (); // obtain the aabb bucket OBB _ obbt = OBB (aabb) of a Sprite3D object; // create an obb Bucket


2. the collision detection method of the OBB box is usually based on the Separation axis theorem. First, we will briefly describe the Separation axis theorem (separating axis theorem ), through the separation axis theorem, we can draw the following conclusion: if we can find an axis, the two convex shapes do not overlap the projection on the axis, then the two shapes do not overlap. If this axis does not exist and those shapes are convex, you can determine that the two shapes are intersecting (concave is not applicable, such as the crescent shape, even if the split axis is not found, the two crescent shapes may not be intersecting ). This theorem can also be understood as follows. If we can find A straight line and make the box A completely on one side of the straight line and the Box B completely on the other side, the two boxes will not overlap. This straight line becomes the separation line (known as the separation plane in the 3D World), and must be perpendicular to the Separation Axis.
Here we will first use the OBB in the two-dimensional world for demonstration. After understanding the principle, the OBB of the three-dimensional object is very easy to understand, as shown in Figure 2-1.
In Figure 2-1, for A separation axis L, if the projection radius of the surrounding Box A and the surrounding Box B on the axis L and the projection distance less than the center distance of the surrounding box in the L, then, the box A and the Box B are separated. The formula is: "T * L |> rA + rB. In Cocos2d-x 3.3beta0, this method is not used to verify the intersection. the method used by the Cocos2d-x is to take the projection coordinates of the maximum and minimum points of object A and object B, then compare the maximum vertex of A with the minimum vertex of B, and the minimum vertex of B with the maximum vertex of. Note: although this is a two-dimensional image, in fact, the projection of a three-dimensional drawing on the Separation Axis is the same as that of a two-dimensional image. It is a line segment. Now that we know the principle of the separation axis theorem, the following describes how to select the Separation Axis. As there may be countless potential separation axes, we don't have to verify them one by one, but just select several testable axes. For example, the convex surface of the OBB box selected in the Cocos2d-x are cuboid, we take the collision of cuboid as an example, the collision of two cuboid can be attributed to the following combination: surface-plane collision, surface-side collision, and edge-side collision (vertices are considered as part of edges ). In fact, when obtaining the Separation Axis, you only need to take the three axes of the first box and the three axes of the second box respectively, and 9 axes perpendicular to a certain axis (the other separation axes are the axes parallel to one of the 15 separation axes, and the values of the projected line segments are the same, no need to verify ).
Here, I will explain what the following nine axes are perpendicular to A certain axis. The specific method is to take the vector of one side of the X axis of the box A first, take another side vector in the X axis direction of the Box B, perform cross product on the two vectors, and obtain the direction vector of A vector perpendicular to A and B, the result is the split axis to be used. In this way, take the side vectors in the X axis direction of A and the side vectors in the three axis directions of B for cross product, take the edge vectors of the Y axis of A and the three axes of B for cross product, take the side vector in the Z axis of A and the side vector in the three axis directions of B for cross product. The result is A total of 3x3 separation axes. 2-2: vc/ytcTKuMG/release/28tL/release + 6687 XEMyozsd/KuMG/x/release + 6687i9yc/release/Co7o8cHJlIGNsYXNzPQ = "brush: java; "> # ifndef _ CC_OBB_H __# define _ CC_OBB_H __# include" CCAABB. h "# include" 3d/3dExport. h "NS_CC_BEGINclass CC_3D_DLL OBB {public: OBB (); // default constructor/** constructor initializes an OBB Box Based on an AABB box */OBB (const AABB & aabb ); /** constructor initializes an OBB box */OBB (const Vec3 * verts, int num) based on the vertex information ); /** determine whether the point is in an OBB-enclosed box */bool containPoint (const Vec3 & point) const; /** specify the values of OBB member variables */void set (const Vec3 & center, const Vec3 & _ xAxis, const Vec3 & _ yAxis, const Vec3 & _ zAxis, const Vec3 & _ extents);/** reset the function to set the memory block occupied by the current OBB object to zero */void reset (); /* For the Z axis negative direction of the surround box * verts [0]: Top left coordinate * verts [1]: Bottom left coordinate * verts [2]: coordinate of the lower right vertex * verts [3]: coordinate of the upper right vertex ** oriented to the square direction of the Z axis of the surrounding box * verts [4]: coordinate of the upper right vertex * verts [5]: coordinate of the lower right vertex * verts [6]: coordinate of the lower left vertex * verts [7]: coordinate of the upper left vertex */void getCorners (Vec3 * verts) const; /** check whether it is in conflict with other OBB boxes */bool intersects (const OBB & box) const; /*** convert the OBB box by the given transformation matrix */void transform (const Mat4 & mat); protected: /** project points to the target axis */float projectPoint (const Vec3 & point, const Vec3 & axis) const; /** calculate the maximum and minimum projection values */void getInterval (const OBB & box, const Vec3 & axis, float & min, float & max) const; /** use */Vec3 getEdgeDirection (int index) const to obtain the edge vector; /** use */Vec3 getFaceDirection (int index) const to obtain the direction vector of the plane to obtain the Separation Axis; public: Vec3 _ center; // center point/* the following three variables are orthogonal unit vectors, which define the x, y, and Z axes of the current OBB box for vector projection */Vec3 _ xAxis; // enclose the unit vector Vec3 _ yAxis in the X axis of the box; // The unit vector Vec3 _ zAxis in the Y axis of the box. // enclose the unit vector Vec3 _ extents in the Z axis of the box; // 3 1/2 sides long, half length, half width, half height}; NS_CC_END # endif
The code for CCOBB. cpp is as follows:
# Include "3d/CCOBB. h "NS_CC_BEGIN # define ROTATE (a, I, j, k, l) g =. m [I + 4 * j]; h =. m [k + 4 * l];. m [I + 4 * j] = (float) (g-s * (h + g * tau);. m [k + 4 * l] = (float) (h + s * (g-h * tau )); // generate the covariance matrix static Mat4 _ getConvarianceMatrix (const Vec3 * vertPos, int vertCount) {int I; Mat4 Cov; double S1 [3]; double S2 [3] [3]; s1 [0] = S1 [1] = S1 [2] = 0.0; s2 [0] [0] = S2 [1] [0] = S2 [2] [0] = 0.0; s2 [0] [1] = S2 [1] [1] = S2 [2] [1] = 0.0; s2 [0] [2] = S2 [1] [2] = S2 [2] [2] = 0.0; // get center of mass for (I = 0; I
 
  
3 & fabs (dmip) + g = fabs (dmip) & fabs (dmiq) + g = fabs (dmiq) {. m [ip + 4 * iq] = 0.0;} else if (fabs (. m [ip + 4 * iq])> tresh) {h = dmiq-dmip; if (fabs (h) + g = fabs (h) {t = (. m [ip + 4 * iq])/h;} else {theta = 0.5 * h/(. m [ip + 4 * iq]); t = 1.0/(fabs (theta) + sqrt (1.0 + theta * theta); if (theta <0.0) t =-t;} c = 1.0/sqrt (1 + t * t); s = t * c; tau = s/(1.0 + c ); h = t *. m [ip + 4 * iq]; _ getElement (z, ip)-= (float) h; _ getElement (z, iq) + = (float) h; _ getElement (d, ip)-= (float) h; _ getElement (d, iq) + = (float) h;. m [ip + 4 * iq] = 0.0; for (j = 0; j <ip; j ++) {ROTATE (a, j, ip, j, iq );} for (j = ip + 1; j <iq; j ++) {ROTATE (a, ip, j, j, iq) ;}for (j = iq + 1; j <n; j ++) {ROTATE (a, ip, j, iq, j) ;}for (j = 0; j <n; j ++) {ROTATE (v, j, ip, j, iq) ;}nrot ++ ;}}for (ip = 0; ip <n; I P ++) {_ getElement (B, ip) + = _ getElement (z, ip); _ getElement (d, ip) = _ getElement (B, ip ); _ getElement (z, ip) = 0.0f ;}} v. transpose (); * vout = v; * dout = d; return;} // create the OBB box orientation matrix static Mat4 _ getOBBOrientation (const Vec3 * vertPos, int num) {Mat4 Cov; // create a 4*4 matrix if (num <= 0) return Mat4: IDENTITY; // return unit matrix Cov = _ getConvarianceMatrix (vertPos, num ); // create a covariance matrix // now get eigenvectors Mat4 Evecs; Vec3 Evals; _ getEigenVectors (& Evecs, & Evals, Cov); // evaluate the feature vector Evecs. transpose (); // transpose return Evecs;} // default constructor OBB: OBB () {// data reset ();} // The OBB box is generated by an AABB box. OBB: OBB (const AABB & aabb) {// data reset (); // center _ center = (aabb. _ min + aabb. _ max); _ center. scale (0.5f); // The unit matrix of the axis rotation matrix _ xAxis = Vec3 (1.0f, 0.0f, 0.0f); _ yAxis = Vec3 (0.0f, 1.0f, 0.0f ); _ zAxis = Vec3 (0.0f, 0.0f, 1.0f); // half-size storage half-length half-width half-height _ extents = Abb. _ max-aabb. _ min; _ extents. scale (0.5f);} // constructor initializes an OBB enclosed box OBB: OBB (const Vec3 * verts, int num) {if (! Verts) return; // If verts does not exist, return reset (); // data reset Mat4 matTransform = _ getOBBOrientation (verts, num ); // create a box orientation matrix/* matTransform is an orthogonal matrix, so its inverse matrix is its transpose; a' = E (E is the matrix of units, a' indicates the transpose matrix of matrix A.) A is called an orthogonal matrix */matTransform. transpose (); // calculate the transpose of the matTransform matrix (this is equivalent to finding the Inverse Moment) Vec3 vecMax = matTransform * Vec3 (verts [0]. x, verts [0]. y, verts [0]. z); Vec3 vecMin = vecMax; for (int I = 1; I <num; I ++) {Vec3 vect = matTransform * Ve C3 (verts [I]. x, verts [I]. y, verts [I]. z); vecMax. x = vecMax. x> vect. x? VecMax. x: vect. x; vecMax. y = vecMax. y> vect. y? VecMax. y: vect. y; vecMax. z = vecMax. z> vect. z? VecMax. z: vect. z; vecMin. x = vecMin. x <vect. x? VecMin. x: vect. x; vecMin. y = vecMin. y <vect. y? VecMin. y: vect. y; vecMin. z = vecMin. z <vect. z? VecMin. z: vect. z;} matTransform. transpose (); _ xAxis = Vec3 (matTransform. m [0], matTransform. m [1], matTransform. m [2]); _ yAxis = Vec3 (matTransform. m [4], matTransform. m [5], matTransform. m [6]); _ zAxis = Vec3 (matTransform. m [8], matTransform. m [9], matTransform. m [10]); _ center = 0.5f * (vecMax + vecMin); _ center * = matTransform; _ xAxis. normalize (); _ yAxis. normalize (); _ zAxis. normalize (); _ extents = 0.5f * (VecMax-vecMin);} // determines whether bool OBB: containPoint (const Vec3 & point) is in the OBB box) const {// equivalent to converting the coordinate points from the world coordinate system to the object Coordinate System in the OBB box. Vec3 vd = point-_ center; /* The dot method is used to calculate the dot product. Because _ xAxis is the unit vector vd and _ xAxis click is the projection in the _ xAxis direction */float d = vd. dot (_ xAxis); // calculate the x-direction projection d // determine whether the projection is longer than the half-length in the square direction of x or less than the half-length in the negative direction of x if (d> _ extents. x | d <-_ extents. x) return false; // if the condition is met, it is not in the surrounding box. d = vd. dot (_ yAxis); // calculate y-direction projection // Similarly, if (d> _ extents. y | d <-_ ex Tents. y) return false; d = vd. dot (_ zAxis); // calculates the z-direction projection if (d> _ extents. z | d <-_ extents. z) return false; return true;} // specify the variable value void obb in the obb box: set (const Vec3 & center, const Vec3 & xAxis, const Vec3 & yAxis, const Vec3 & zAxis, const Vec3 & extents) {_ center = center; _ xAxis = xAxis; _ yAxis = yAxis; _ zAxis = zAxis; _ extents = extents ;} // reset void OBB: reset () {memset (this, 0, sizeof (OBB); // set the memory block of OBB to zero }// Obtain the vertex information void OBB: getCorners (Vec3 * verts) const {Vec3 extX = _ xAxis * _ extents. x; // Vec3 extY = _ yAxis * _ extents. y; // y direction component Vec3 extZ = _ zAxis * _ extents. z; // z-direction component // verts [0] in the positive direction of the z axis = _ center-extX + extY + extZ; // verts [1] = _ center-extX-extY + extZ; // verts [2] = _ center + extX-extY + extZ; // verts [3] = _ center + extX + extY + extZ; // verts in the negative direction of the zaxis [4] = _ center + extX + extY-extZ; // verts [5] = _ center + extX-extY-extZ; // verts [6] = _ center-extX-extY-extZ; // verts [7] = _ center-extX + extY-extZ; // top left vertex coordinate} // project the vertex to the coordinate axis float OBB: projectPoint (const Vec3 & point, const Vec3 & axis) const {float dot = axis. dot (point); // point product float ret = dot * point. length (); return ret;} // calculate the maximum and minimum projection values void OBB: getInterval (const OBB & B Ox, const Vec3 & axis, float & min, float & max) const {Vec3 corners [8]; box. getCorners (corners); // obtain the float value of the vertex information in the bounding box; // project eight points, respectively, to obtain the maximum and minimum values of min = max = projectPoint (axis, corners [0]); for (int I = 1; I <8; I ++) {value = projectPoint (axis, corners [I]); min = MIN (min, value); max = MAX (max, value) ;}// Vec3 OBB: getEdgeDirection (int index) const {Vec3 corners [8]; getCorners (corners); // obtain the information of eight vertices. Vec 3 tmpLine; switch (index) {case 0: // tmpLine = corners [5]-corners [6]; tmpLine. normalize (); // normalized break; case 1: // tmpLine = corners [7]-corners [6]; tmpLine. normalize (); break; case 2: // tmpLine = corners [1]-corners [6]; tmpLine. normalize (); break; default: CCASSERT (0, "Invalid index! "); Break;} return tmpLine;} // Vec3 OBB: getFaceDirection (int index) const {Vec3 corners [8]; getCorners (corners ); // obtain eight vertex information. Vec3 faceDirection, v0, v1; switch (index) {case 0: // The calculation result is a vector parallel to the Z axis. v0 = corners [2]-corners [1]; // vector v1 = corners [0]-corners [1] of the center-> bottom-right corner of the face + z; // The result of the cross Product of the lower left vertex> the vector of the upper left vertex/* two vectors is perpendicular to the vector of the original two multiplied Vectors */Vec3: cross (v0, v1, & faceDirection); // calculate the cross product result of v0 and v1 and store it in faceDirect. Ion/* normalization here is equivalent to finding x, the normal vector of the plane where the Y axis is located */faceDirection. normalize (); break; case 1: // left/right returns a vector that is parallel to the X axis. v0 = corners [5]-corners [2]; v1 = corners [3]-corners [2]; Vec3: cross (v0, v1, & faceDirection); faceDirection. normalize (); break; case 2: // The Upper/lower calculation result is a vector that is parallel to the Y axis. v0 = corners [1]-corners [2]; v1 = corners [5]-corners [2]; Vec3: cross (v0, v1, & faceDirection); faceDirection. normalize (); break; default: CC ASSERT (0, "Invalid index! "); Break;} return faceDirection; // returns the direction vector} // checks whether two OBB boxes overlap bool OBB: intersects (const OBB & box) const {float min1, max1, min2, max2; // the three sides of the current box is equivalent to taking the three axes of the box as the Separation Axis and calculating the projection for (int I = 0; I <3; I ++) {getInterval (* this, getFaceDirection (I), min1, max1 ); // calculate the maximum and minimum projection values of the current surround box on an axis. getInterval (box, getFaceDirection (I), min2, max2 ); // calculate the maximum and minimum projection values of another surround box on an axis. if (max1 <min2 | max2 <min1) return false; // determine whether the projection on the Separation Axis is coincident} // for (int I = 0; I <3; I ++) {getInterval (* this, box. getFaceDirection (I), min1, max1); getInterval (box, box. getFaceDirection (I), min2, max2); if (max1 <min2 | max2 <min1) return false ;}for (int I = 0; I <3; I ++) {for (int j = 0; j <3; j ++) {Vec3 axis; // Vec3: cross (getFaceDirection (I), box. getFaceDirection (j), & axis); // source code Vec3: cross (getEdgeDirection (I), box. getEdgeDirection (j), & axis); // modify the edge vector and perform the cross product getInterval (* this, axis, min1, max1); getInterval (box, axis, min2, max2); if (max1 <min2 | max2 <min1) return false;} return true;} // void OBB is transformed from the OBB box by a given matrix:: transform (const Mat4 & mat) {// new central point Vec4 newcenter = mat * Vec4 (_ center. x, _ center. y, _ center. z, 1.0f); _ center. x = newcenter. x; _ center. y = newcenter. y; _ center. z = newcenter. z; // transform vector _ xAxis = mat * _ xAxis; _ yAxis = mat * _ yAxis; _ zAxis = mat * _ zAxis; _ xAxis. normalize (); // normalize _ yAxis. normalize (); _ zAxis. normalize (); Vec3 scale, trans; Quaternion quat; // a four-dimensional rotation mat can be expressed by a four-dimensional element in length. decompose (& scale, & quat, & trans); // half-length, half-width, and half-height _ extents. x * = scale. x; _ extents. y * = scale. y; _ extents. z * = scale. z;} NS_CC_END
 




Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.