Author: weiqubo
Link: http://software.intel.com/zh-cn/blogs/2012/02/14/400009793? Cid = Sw: prccsdn2160
Almost all 3D games are inseparable from collision detection-collision detection between objects or between objects and scenes. In the real world, you naturally cannot pass through the wall, so many people naturally ignore the existence of the collision detection process when playing various 3D games. However, the collision detection process is important. Without it, you will fly around without blocking in CS-if you consider gravity, it will keep falling, until the number of points overflows (or you can't stand this long process and leave the game. Collision Detection is implemented during programming. Do not think that collision detection is performed by the video card while displaying 3D images-this is naive-there is no hardware to support collision detection.
After reading this, you may be interested in collision detection, or as a 3D programmer, you are looking for collision detection principles and methods, or I haven't found it for a long time (I am not a little poor: P), so let's look at a very effective and easy-to-understand algorithm.
This algorithm detects collision between objects and scenes. It requires that your scenario is composed of many triangles. Currently, almost all 3D program scenes or objects are composed of many triangles, so this is not a problem. In addition, you need to record the position of the object in the previous frame and the current frame. This is also easy to do. In addition, everything else is required. Let's take a look at its principles.
I. Principles
First, calculate the position of the object in the frame to be rendered (current frame) based on the motion of the object or the user input (the collision detection problem does not need to be considered at this time). Then, traverse every triangle in a loop scenario. In the loop process, perform the following operations:
1. Find the plane where the current triangle is located. We call it plane s. Perform a D translation along the normal direction of the plane to indicate the distance between the object and the plane.
2. determine the relationship between the oldposition and newposition of the object in the previous frame and the position in the current frame and the plane S: if the previous frame is before the plane and the current frame is behind the plane, as shown in:
Then proceed with step 3.
Otherwise, skip 3, 4, and do 5.
3. Because the first and second frames of an object are on the opposite side of the plane, it indicates that the object passes through the plane S. However, it cannot be said that an object has a collision with a triangle. Because the plane has no boundaries, we need to further judge whether the object passes through the plane s within the three sides of the triangle. The three sides of a triangle are perpendicular to the plane ps1, ps2, and PS3 of the triangle. And point their normal to the inside of the triangle, as shown in:
In order to reflect the shortest distance that an object and a triangle can be close to, the three planes also need to make a translation L, just along the negative direction of their normal:
We will rely on these three planes to determine whether an object passes through the plane s within the scope defined by the three sides of the triangle. However, if a triangle has a sharp acute angle, the defined area is too large, as shown in figure4. So we need the other three planes that are parallel to them: PS4, ps5, and ps6 to split the output acute angle (figure5 ). It is easy to generate these three planes. You only need to move ps1, ps2, and PS3 to the equal vertices of their normal direction, and then add L.
Now, determine whether the object location is within these six planes. If yes, perform 4; otherwise, perform 5.
4. We have been able to determine the collision between the object and the current triangle. At this time, we can modify the position newposition of the current frame so that the motion of the object is parallel to that of the plane S.
5. We have been able to determine that the object has not collided with the current triangle. Make the next triangle into the current triangle and return to 1.
After all triangles are traversed once, the position newposition of the object is after collision detection and correction. Rendering objects and scenes at this position, and updating the old position before the next frame to the current frame position (oldposition = newposition ).
In short, the principle of this algorithm is to give a triangle-determine whether the object passes through the surface of the triangle-and then determine whether the object passes through the triangle. Let's take a look at its specific implementation.
II. Specific implementation
In specific implementation, we may encounter the following problems.
First, how can we get the plane where the triangle is located? A plane can be represented by a normal vector and its distance from the origin. assume that we have a Triangle ABC and Its plane is S, as shown in:
The vertex positions are three three-dimensional vectors A, B, and C. First, we get the method vector N of the triangle: (The following vector represents the three-dimensional vector, and float represents the floating point scalar)
Vector V1 = B-a' edge vector directed by A to B
Vector v2 = C-a' edge vector directed by A to C.
Vector n = normalize (V1 x V2) 'X indicates the cross multiplication. Note that the cross multiplication is ordered. If V1 and V2 are interchangeable, The result vector is reversed. Normalize indicates unitization of the result. The resulting n is the triangle's normal vector.
Vector S. N = n' method vector of the triangle, that is, the method vector of the Plane s.
Then, we calculate the distance between the plane and the origin s.d:
Float s.d = N * a' * represents the point multiplication. The calculated result is the projection length from vertex A to normal S. N, that is, the distance from s.d, to a scalar.
With the normal vector and distance, it can represent a plane. To translate a plane, you only need to modify the s.d value.
So how can we determine the side of an object on the plane? You only need to compare the projection length of the object position on the plane normal vector and the D value of the plane. Assume that our object location is represented by a 3-dimensional vector p.
Float dp = S. N * P' point multiplication. DP is the projection length of the object position on the Plane s normal n. It is a scalar.
If (Dp-s.d)> 0, on the front of Plane s.
If (Dp-s.d) m_pmesh = NULL)
Return e_fail;
If (lpps = NULL)
Return e_fail;
If (lpmap-> m_dwnumindices = 0)
Return e_fail;
If (lpmap-> m_dwnumvertices = 0)
Return e_fail;
In DirectX 8 graphics, the mesh model of the scenario consists of vertex buffering and index buffering. The vertex buffer stores information about all vertices. Each of the three elements in the index buffer represents a triangle. The value of these elements is the index number of the three vertices in the vertex buffer. We can obtain the positions of the three vertices of a triangle. The following code locks the vertices and index Buffering in the mesh model and obtains the pointer to them.
Lpmap-> m_pmesh-> lockindexbuffer (d3dlock_readonly, (byte **) & pindexdata );
Lpmap-> m_pmesh-> lockvertexbuffer (d3dlock_readonly, (byte **) & pvertexdata );
Then, traverse every triangle in the mesh:
For (word I = 0; I m_dwnumindices; I + = 3)
{
Word a = pindexdata [I + 0]; // A: Index of the first vertex of a triangle
Word B = pindexdata [I + 1]; // B: Index of the second vertex of the triangle
Word c = pindexdata [I + 2]; // C: Index of the third vertex of a triangle
D3dxvector3 V1 = pvertexdata [B]. P-pvertexdata [A]. P;
// V1: edge AB Vector
D3dxvector3 v2 = pvertexdata [C]. P-pvertexdata [A]. P;
// V2: edge AC Vector
D3dxvec3cross (& vnormal, & V1, & V2); // use the cross product to obtain the triangle normal vector.
D3dxvec3normalize (& vnormal, & vnormal );
Fdistance = d3dxvec3dot (& vnormal, & pvertexdata [A]. p) + 5.0f;
// The projection length of vertex A on the normal vector, that is, the distance between the plane and the origin.
If (precheckcollision (lpps, & vnormal, fdistance) = 1)
{// If the player passes through the plane of the triangle
If (checkcollision (lpps, A, B, C, & vnormal, pvertexdata) = 1)
{// If it passes through within the three sides of a triangle
// Modify the player's position so that the player cannot penetrate the wall.
Lpps-> vnewpos + = vnormal * (fdistance
-D3dxvec3dot (& vnormal, & lpps-> vnewpos) + 0.2 );
}
}
// Otherwise, continue the loop and determine the next triangle.
}
// The loop ends. You must unlock the vertex and index buffer before exiting.
Lpmap-> m_pmesh-> unlockvertexbuffer ();
Lpmap-> m_pmesh-> unlockindexbuffer ();
Return s_ OK;
}
The following is the code for functions precheckcollision () and checkcollision.
// ================================================ ==============
// Function name: precheckcollision ()
// Function: determines whether a player passes through the current plane.
// Parameter description:
// _ Player_state * lpps: The player status, including location information.
// Vnromal: the normal vector of the Current Plane (unit-based)
// Fdistance: the distance between the current plane and the Origin
// Return value: if further detection is required, 1 is returned.
// Otherwise, 0 is returned.
//-------------------------------------------------
Int precheckcollision (player_state * lpps, d3dxvector3 * pvnormal, float fdist)
{
Float startside, endside;
// Calculate the distance between the player's old position and the plane
Startside = d3dxvec3dot (pvnormal, & lpps-> voldpos)-fdist;
// Calculate the distance between the player's new position and the plane
Endside = d3dxvec3dot (pvnormal, & lpps-> vnewpos)-fdist;
// If the player's old position is before the plane and the new position is behind the plane,
// Indicates that the plane passes through.
If (startside> 0 & endside <= 0) return 1;
Else return 0;
}
// ================================================ ==========
// Function name: checkcollision
// Function: determines whether an object passes through a triangle.
// Parameter description:
// _ Player_state * lpps: The player status, including location information.
// Vertex A, B, C: vertex of a triangle
// The index in the buffer.
// D3dxvector3 * vnormal: normal triangle Vector
// Customvertex * pvertices: pointer to vertex buffer
// Return value: if the player passes through the triangle, 1 is returned.
// Otherwise, 0 is returned.
//----------------------------------------------
Int checkcollision (player_state * lpps, word a, word B, word C, d3dxvector3 * pvnormal, customvertex * pvertices)
{
D3dxvector3 perplanenormal;
// Normal vector of the vertical plane (perpendicular plane)
Float fperplanedist;
// The distance between the vertical plane and the origin.
D3dxvector3 V1;
// Records the vector of the current side of a triangle.
// ================================================ ======================================
// Check whether the object is in the vertical plane of the first edge AB of the triangle
// And within the plane relative to it.
// Calculate the AB edge vector of the triangle.
V1 = pvertices [B]. P-pvertices [A]. P;
// Calculate the normal vector of the vertical plane of the edge.
D3dxvec3cross (& perplanenormal, pvnormal, & V1 );
D3dxvec3normalize (& perplanenormal, & perplanenormal );
// Ensure that the normal vector of the vertical edge points to the inside of the triangle.
If (d3dxvec3dot (& (pvertices [C]. P-pvertices [A]. p), & perplanenormal) voldpos)-fperplanedistvoldpos)-fperplanedist> 0)
Return 0;
// ================================================ ======================================
// Check whether the object is in the vertical plane of the edge BC and its relative plane.
// The steps are similar to those above.
V1 = pvertices [C]. P-pvertices [B]. P;
D3dxvec3cross (& perplanenormal, pvnormal, & V1 );
D3dxvec3normalize (& perplanenormal, & perplanenormal );
If (d3dxvec3dot (& (pvertices [A]. P-pvertices [B]. p), & perplanenormal) voldpos)-fperplanedistvoldpos)-fperplanedist> 0)
Return 0;
// ================================================ ======================================
// Then the vertical plane of the edge Ca and its relative plane.
V1 = pvertices [A]. P-pvertices [C]. P;
D3dxvec3cross (& perplanenormal, pvnormal, & V1 );
D3dxvec3normalize (& perplanenormal, & perplanenormal );
If (d3dxvec3dot (& (pvertices [B]. P-pvertices [C]. p), & perplanenormal) voldpos)-fperplanedistvoldpos)-fperplanedist> 0)
Return 0;
// If the object is out of any six planes above, the function has already returned 0.
// If no result is returned, it indicates that the object is within the six sides,
// Return 1.
Return 1;
}
Note: The above three functions are written by myself based on the principle of the algorithm. Although they run normally in my program, due to the limited level, there will inevitably be omissions, because it is written for routines, it is not very universal. However, this collision detection algorithm in functions is faithfully embodied. In short, we want to further describe the algorithm.
Some improvements
We have always expressed the minimum distance between an object and a plane in a constant. However, this is equivalent to seeing an object as a sphere, which does not reflect some characteristics of the shape of the object. For example, if the length and width of the human body are greater than the height, it is best to regard it as a high elliptical body during collision detection. A simple method to solve this problem is to calculate the minimum distance between the object and the plane based on the normal of the triangle to be determined. When the triangle is steep, the smaller the distance will be. Specific algorithms are provided in references.
About routines
You can click here to download the routines and source code used in this article. Due to the relationship between time and level, this routine is far from perfect, so it is not quite universal and may contain some errors. To run this program, DirectX 8 or a later version is required. To compile the source program, you need the SDK of DirectX 8 or later. (Download from the Download Area on this site ).
Program Control: