2.6 detect collision between cameras and models, walls or terrain
You want to check whether the camera is near the object to prevent it from passing through the object.
Solution
To perform a collision detection between the camera and the model, you should represent the camera as an surround ball and use this surround ball to check the collision with the model's surrounding ball or the surrounding box. For user-defined mesh, such as a wall or terrain, you must first find precise 3D coordinates at any location of the triangle on the wall or terrain.
Working Principle
Camera collisions can be divided into model collisions and triangular mesh collisions with known vertex heights.
Collision between cameras and Models
In this case, you use the camera as a ball. You only need to adjust the ball radius to set the minimum distance between the model and the camera. To detect the collision between the camera ball and the model, you also need to enclose the ball or the box of the model. The ball can be computed using loadmodelwithboundingsphere. This method is described in 4-5 of the tutorial, it stores the ball in the tag attribute of the model. This tag attribute can store any object of the model and is suitable for storing the sphere of the model. Use the following in the loadcontent method:Code:
Mymodel = xnautils. loadmodelwithboundingsphere (ref modeltransforms, "tiny", content );
Collision Detection is required for both mobile cameras and models. If a collision is detected, you will cancel the last change of the camera by restoring the camera position to the initial value. In the update method, make sure that you have saved the initial value:
Protected override void Update (gametime) {gamepadstate = gamepad. getstate (playerindex. one); If (gamepadstate. buttons. back = buttonstate. pressed) This. exit (); mousestate = mouse. getstate (); keyboardstate keystate = keyboard. getstate (); vector3 lastcampos = fpscam. position; fpscam. update (mousestate, keystate, gamepadstate); base. update (gametime );}
After the camera is updated, you need to create a ball that matches the camera's new position. In the following code, you can set the minimum distance of the ball to 1 unit:
Float minimumdistance = 1.0f; boundingsphere camerasstance = new boundingsphere (fpscam. Position, minimumdistance );
With the updated camera ball and model ball, you can detect the intersection between the two. If the intersection is detected, the camera is restored to the previous position:
Boundingsphere origmodelsphere = (boundingsphere) mymodel. Tag; boundingsphere transmodelsphere = xnautils. transformboundingsphere (origmodelsphere, worldmatrix); If (camerasphere. Contains (transmodelsphere )! = Containmenttype. disjoint) fpscam. Position = lastcampos;
If the model is moved to another location or scaled through the world matrix, you should also move/zoom the surrounding ball accordingly, which can be achieved by using transformboundingsphere.
The following code checks whether the distance between the camera's ball and the model ball is less than one unit.
Collision between camera and terrain
If you want to detect the collision between the camera and your custom vertex mesh (such as terrain), you need to use triangle collision. The method used in this chapter is applicable to the case where the vertex vertical and horizontal coordinates are equal spacing.
If the vertex height information is stored in Y coordinates, this means that the distance between X and Z coordinates of all vertices is the same, for this reason, you can know the square on which the camera is located. For example, if the camera position is (10.3f, 8.7f, 5.1f), you can know that the camera is composed of four vertices (10 ,.., 5), (11 ,.., 5), (10 ,..., 6) and (11 ,..., 6) a height above the constructed Square. The ellipsis in the brackets indicates the height of these vertices, which are defined during mesh creation. You store these heights in an independent array, or you can obtain these heights from the vertex buffer (this is not the preferred method ).
But how do I know the height difference between the camera and the terrain below? The simplest way is to take the camera position to the nearest position of the vertex and check whether the camera is above the vertex. if the camera is below the terrain, adjust the height of the camera accordingly:
Protected override void Update (gametime) {gamepadstate = gamepad. getstate (playerindex. one); If (gamepadstate. buttons. back = buttonstate. pressed) This. exit (); mousestate = mouse. getstate (); keyboardstate keystate = keyboard. getstate (); fpscam. update (mousestate, keystate, gamepadstate); float treshold = 3.0f; float terrainheight = terrain. getclippedheightat (fpscam. position. x,-fpscam. position. z); If (fpscam. position. Y <terrainheight + treshold) {vector3 newpos = fpscam. position; newpos. y = terrainheight + treshold; fpscam. position = newpos;} base. update (gametime );}
The getclippedheightat method returns the height of the terrain vertex. For more information, see tutorial 5-9. You can change the threshold value to set the minimum threshold value for the height difference between the camera and the terrain. The code above will adjust the height of the camera and keep the height difference between the camera and the terrain at threshold.
Note:The two parameters of the getclippedheightat method are both positive values, because these two parameters are used as the index of the query matrix, and the forward direction is the Negative Z axis direction, so you need to add a "-" sign before the zcoordinate to make it a positive value.
Because the height is obtained from neighboring vertices, The getclippedheightat method returns different values. The above code causes the camera to jump when moving the triangle. To ensure smooth transition, you can use the getexactheightat method of the terrain object. This method is explained in tutorial 5-9. This method can obtain the exact height of the terrain points lower than the camera position:
Float terrainheight = terrain. getexactheightat (fpscam. position. X,-fpscam. position. z );
This method is better when the camera or model is moving slowly on the terrain.
Collision between camera and wall
A wall usually consists of only two triangles, so it is a simplified form of camera-terrain collision. You can use the getexactheightat method described in tutorial 5-9 to obtain the precise 3D points of the wall in front of the camera.
Code
We have all the code for the update method.