Welcome to join the Cocos2d-x Exchange Group: 193411763
When reproduced, please indicate the original source: http://blog.csdn.net/u012945598/article/details/39927911
--------------------------------------------------------------------------------------------------------------- --------------------------------------------
1. Three-dimensional pickup technology
In 3D games usually have such a demand, the user can choose some objects in the 3D world, such as drag-and-drop operations, then need to program by the two-dimensional screen to convert the point coordinates into a three-dimensional world coordinates, and compare, this process needs to use three-dimensional pickup.
The basic principle of three-dimensional pickup is not complicated, and we still analyze it with the Cocos2d-x 3.3beta0 version. Pick thought can be simply understood as: first get the coordinates of the touch point on the screen, and then based on the camera projection matrix and the touch point on the screen to calculate a ray Ray, note that normally after the intersection with the Ray and the intersection of the point of origin of the closest points of the ray is located in the bounding box, This bounding box is the bounding box that should be touched, but in fact Cocos2d-x 3.3BETA0 does not do this, the problem is discussed in the following article.
2. Schematic diagram
The three-dimensional pickup principle is shown in Figure 1-1:
Figure 1-1
In this case, the ray actually intersects object A and object B, but actually object A is supposed to be a touch object. However, the Cocos2d-x 3.3beta0 has not yet done so, only to determine whether the ray and a current bounding box exists in the intersection. Here's a look at the Cocos2d-x 3.3beta0 in the Obb bounding box demo section of the Code:
void Sprite3dwithobbperfromancetest::ontouchesbegan (const std::vector<touch*>& touches, Event* Event) { For (auto touch:touches) { Auto location = Touch->getlocationinview (); Gets the coordinates of the touch point in the screen coordinate system if (_obb.size () > 0)//determines if the obb bounding box is present on the screen { _intersetlist.clear (); Ray Ray; x ///////based on the screen coordinate point coordinates, the starting point and direction vector Calculateraybylocationinview (&ray,location) of the ray in the world coordinate system are computed. for (int i = 0; i < _obb.size (); i++) { if (ray.intersects (_obb[i]))//Determine if the ray and bounding box intersect { _ Intersetlist.insert (i); return;}}}}
When the algorithm is traversing the bounding box, once the resulting ray and a bounding box collide, the loop terminates and the bounding box of the object is taken. But if the two bounding boxes overlap together, it should be judged which bounding box is closer to the beginning of the ray, and closer is the box that should be touched. This is equivalent to the two overlapping boxes which are first traversed in front of the container, which is the equivalent of touching the one.
Leave the above issues behind, back to figure 1-1. As shown in Figure 1-1, the final thing to do is to find the intersection of the Ray and the near plane and the far plane according to the touch point on the screen, so that we can get the ray we need. In Cocos2d-x 3.3beta0, Ray represents the Ray class, which contains the starting point and the direction vector of the ray, and provides an algorithm for collision detection with the AABB bounding box and the obb bounding box. Also in the preceding code, a method is called: calculateraybylocationinview ( Span class= "S1" style= "font-family: ' Microsoft Yahei ';" >ray * ray, const &NBSP; VEC2 & location. This method is based on the screen coordinate system to find a point of a ray of the method, the following look at the implementation:
Converts a point in the screen to coordinates in the world coordinate system void Sprite3dwithobbperfromancetest::unproject (const mat4& viewprojection, const size* Viewport, vec3* src, vec3* DST) {assert (DST); ASSERT (Viewport->width! = 0.0f && viewport->height! = 0.0f); Calculates the coordinates of a point in the camera's coordinate system, using the coordinates of the touch point and the linear correlation of the camera's near plane coordinates Vec4 screen (src->x/viewport->width, (viewport->height-src-> y))/Viewport->height, src->z, 1.0f); screen.x = screen.x * 2.0f-1.0f; SCREEN.Y = SCREEN.Y * 2.0f-1.0f; SCREEN.Z = screen.z * 2.0f-1.0f; The coordinates obtained in the camera coordinate system are transformed by the inverse matrix of the camera matrix to obtain its world coordinate viewprojection.getinversed (). Transformvector (screen, &screen); Homogeneous coordinates normalization if (SCREEN.W! = 0.0f) {screen.x/= screen.w; SCREEN.Y/= SCREEN.W; Screen.z/= SCREEN.W; }//Save the point of world coordinates dst->set (screen.x, SCREEN.Y, screen.z);} computed ray void Sprite3dwithobbperfromancetest::calculateraybylocationinview (ray* ray, const vec2& location) {Auto Dir = Director::getinstance (); AuTo view = Dir->getwinsize (); Gets the window size used to calculate the touch point position in the camera coordinate system Mat4 Mat = Dir->getmatrix (Matrix_stack_type::matrix_stack_modelview); Gets the top element of the projection matrix stack (that is, the copy of the top element of the original stack, carrying the transformation information of the parent node) mat = Dir->getmatrix (matrix_stack_type::matrix_stack_projection); VEC3 src = Vec3 (location.x, LOCATION.Y,-1); VEC3 Nearpoint; Near Plane point Unproject (Mat, &view, &SRC, &nearpoint);//Calculate the coordinates of the near-planar point in the world coordinate src = Vec3 (location.x, LOCATION.Y, 1); VEC3 FarPoint; Far plane point Unproject (Mat, &view, &SRC, &farpoint);//Calculate the coordinates Vec3 direction of the far plane point in the world coordinate system; Direction Vector vec3::subtract (farPoint, Nearpoint, &direction); The far plane point subtracts the near plane point to find the direction vector direction.normalize (); Normalization of ray->_origin = Nearpoint; Ray start position ray->_direction = direction; X-ray Direction vector}
3.ray-aabb Collision DetectionAfter the ray is done, it is necessary to detect the collision with the bounding box, as shown in the previous code, when doing collision detection, the Ray class in Cocos2d-x 3.3BETA0 provides us with the intersects () method, The parameters of this method have Obb object and Aabb object two kinds, in fact, eventually converted to AABB detection, and finally look at the collision detection related code:
BOOL Ray::intersects (const aabb& AABB) const{Vec3 ptonplane;//The intersection of a ray with the bounding box Vec3 min = aabb._min;//aabb bounding box minimum point coordinates VEC3 max = Aabb._max; Aabb bounding box maximum point coordinate const vec3& origin = _origin; X-ray starting point const vec3& dir = _direction; Direction vector float T; Determine the intersection of the ray and each plane separately//determine if there is an intersection between the Ray and the x-axis direction of the bounding box if (dir.x! = 0.f)//X-axis direction component of the ray is not 0 if the x-axis component of the ray direction vector is 0, the ray cannot pass through two faces in the x-axis direction { /* Use the ray to intersect the plane with the formula to find the intersection */if (dir.x > 0)//If the ray is shifted along the x-axis positive direction t = (min.x-origin.x)/dir . x; else//The ray is offset along the x axis in negative direction t = (max.x-origin.x)/dir.x; if (T > 0.f)//t>0, the ray intersects the plane {Ptonplane = origin + T * DIR;//calculate the intersection coordinates//determine if the intersection is within the current polygon if (Min.y < ptonplane.y && Ptonplane.y < max.y && Min.z < ptonplane.z && Ptonplane . z < max.z) {return true;//Ray has an intersection with bounding box}}}//If the ray has a component along the y-axis to determine whether the package The y-axis direction of the box has an intersection if (dir.y! = 0.f) {if (Dir.y > 0) t = (MIN.Y-ORIGIN.Y)/dir.y; else T = (MAX.Y-ORIGIN.Y)/dir.y; if (T > 0.f) {Ptonplane = origin + T * DIR; if (Min.z < ptonplane.z && Ptonplane.z < max.z && min.x < ptonplane.x && Ptonplane.x < max.x) {return true; }}}//If the ray has a component along the z-axis to determine if there is an intersection with the bounding box y direction if (dir.z! = 0.f) {if (Dir.z > 0) t = (min.z-or IGIN.Z)/Dir.z; else T = (max.z-origin.z)/dir.z; if (T > 0.f) {Ptonplane = origin + T * DIR; if (min.x < ptonplane.x && ptonplane.x < max.x && MIN.Y < ptonplane.y && Ptonplane.y < MAX.Y) {return true; }}} return false;}
Cocos2d-x Tutorials (35)-three-dimensional pickup ray-aabb collision detection algorithm