Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 30 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
30
Dung lượng
310,9 KB
Nội dung
248 MATRIX math is a branch of linear algebra, and all 3D graph- ics programmers can benefit from understanding it. In video game development, matrices are used to store data such as vertices and infor- mation about how to transform an object. Matrices are simply grids of rows and col- umns, but they are essential for scaling, rotating, and translating objects in 3D space. You will have noticed by now that matrix calculations are used throughout your XNA and shader code for performing transformations, controlling your camera, and even drawing 3D models. Understanding how these matrix methods work will pro- vide you with a better understanding of 3D game engines. Most of the time, you can get away with just using XNA matrix methods to automatically create matrices and to implement your transformations. However, for complex vector transformations, you may need to be able to build your own matrices for the calculations. In Chapter 8, a matrix is manually created to compute the flight path of an air- plane. In Chapter 19, a matrix is manually built to implement a vector transforma- tion that determines the starting position and direction of a rocket. In cases like these, understanding the matrix math can definitely help to simplify your transformations. M ATRIX MULTIPLICATION This section introduces matrix multiplication and prepares you for performing man- ual transformations later in the chapter. The product of two matrices is obtained by multiplying the rows of matrix A by the columns of matrix B (where matrix A is on the left side of the operator). For the multiplication to be possible, the total number of columns in matrix A must equal the total number of rows in matrix B. Matrix Types XNA’s Matrix type enables storage of 3×3 matrices (3 rows by 3 columns) and 4×4 matrices (4 rows by 4 columns). Each cell in the matrix grid can be accessed by refer- encing the matrix and suffixing it with the cell’s row and column, where the top-left cell begins at row 1, column 1. Each cell stores a float: float cellvalue = Matrix matrix.MRC For example, matrix.M11 represents the value in row 1, column 1. Ma- trix.M13 represents the value in row 1, column 3. Matrix Multiplication Example: 1×4 Matrix * 4×4 Matrix This example shows how to multiply a 1×4 matrix by a 4×4 matrix. We’ll first show the multiplication done by hand so that you can see each step of the calculation. 249 Later, the same operation will be shown in code. For this example, a vector with X=2, Y=1, Z=0, and W=0 will be multiplied by a 4×4 matrix. Manual Calculation To set up the equation, the vector is placed on the left side of the multiplication operator, and the 4×4 matrix is placed on the right, as shown here: | 2 1 0 0 | X | 2 1 3 1 | | 1 2 4 1 | | 0 3 5 1 | | 2 1 2 1 | The row on the left is multiplied by each column on the right. The following for- mula is used for each of the four columns of vector C, where A represents the matrix on the left and B represents the matrix on the right: for(int c=1; c<=4; c++) C 1c = A 11 *B 1c + A 12 *B 2c + A 13 *B 3c + A 14 *B 4c Implementing the formula gives you the following: |( 2*2 + 1*1 ( 2*1 + 1*2 ( 2*3 + 1*4 ( 2*1 + 1*1 |+ 0*0 + 0*2) + 0*3 + 0*1) + 0*5 + 0*2) + 0*1 + 0*1) = | 5 4 10 3 | The product ofA*B,therefore, is a new vector with X=5, Y=4, Z=10, and W=3. Calculation in Code The previous computation will now be performed in code. This allows you to print the calculation results in the game window. To begin, start with the solution for the “Font Example: Displaying Text in the Game Window” section of Chapter 13. This solution can be found in the Solutions folder on this book’s website. Since we will be displaying rows and columns of numeric data, we need to have a suitable font type to align the text in each cell. To keep things simple, this example uses the Courier New font, which is a monospace, or nonproportional, font, which means that all characters are the same width. A monospace font ensures that each character is the same pixel width. This is useful because having alphabetical and nu- meric characters of the same width simplifies the data formatting calculations. Once you have the project open, to improve readability, add the Cell() method so you can create an evenly spaced string for each cell. This method will right-align the columns when they are displayed in a matrix grid. Cell() first formats the data in each cell so it appears as a floating-point number with two decimal places. Then Cell() compares the length of the data string with the number of spaces allotted for CHAPTER 16 Matrices each cell. Cell() does this by adding extra spaces until the total character count for the string matches the number of spaces allotted for each cell. When the string has been created, it is returned to the calling function: public string Cell(float cell){ string cellDisplay = cell.ToString("N2"); // 2 decimals const int CELL_WIDTH = 8; // 8 chars wide int numDigits = cellDisplay.Length; // right align text and add padding on left for (int i = 0; i < CELL_WIDTH - numDigits; i++) cellDisplay = " " + cellDisplay; return cellDisplay; } To display the cell data (for the product matrix) as text in the game window, you will require the DrawMatrix() method. Add it to your game class so that you can convert each cell of the product matrix to a string, combine cells to form each row of the matrix, and then draw each row of the matrix in the window. public void DrawMatrix(Matrix C){ String[] row = new String[4]; // output strings row[0] = Cell(C.M11) + Cell(C.M12) + Cell(C.M13) + Cell(C.M14); row[1] = Cell(C.M21) + Cell(C.M22) + Cell(C.M23) + Cell(C.M24); row[2] = Cell(C.M31) + Cell(C.M32) + Cell(C.M33) + Cell(C.M34); row[3] = Cell(C.M41) + Cell(C.M42) + Cell(C.M43) + Cell(C.M44); spriteBatch.Begin(SpriteBlendMode.AlphaBlend, // enable transparency SpriteSortMode.Immediate, // use manual order SaveStateMode.SaveState); // preserve 3D settings for (int i = 0; i < 4; i++){ // draw 4 matrix rows Rectangle safeArea = TitleSafeRegion(row[i], spriteFont); float height = spriteFont.MeasureString(row[i]).Y; spriteBatch.DrawString( spriteFont, // font row[i], // row string new Vector2(safeArea.Left, // top left pixel safeArea.Top+(float)i*height), Color.Yellow); // color MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 250 251 } spriteBatch.End(); } When you open the solution, you must add the MultiplyMatrix() method to the game class so it can initialize two matrices and calculate their product. For this example, the code declares matrix A and initializes it to store the vector in the first row. Initially, when the constructor for the Matrix type is referenced, all cells in ma- trix A are initialized to 0. The vector’s X, Y, Z, and W components are assigned to the four cells of the first row of matrix A. The cell data for the matrix on the right side of the operator is assigned to matrix B; then A and B are multiplied together to generate the product matrix. public Matrix MultiplyMatrix(){ Matrix A = new Matrix(); Matrix B = new Matrix(); // store vector in first row - all other cells equal 0 A.M11 = 2.0f; A.M12 = 1.0f; A.M13 = 0.0f; A.M14 = 0.0f; // initialize matrix B B.M11 = 2.0f; B.M12 = 1.0f; B.M13 = 3.0f; B.M14 = 1.0f; B.M21 = 1.0f; B.M22 = 2.0f; B.M23 = 4.0f; B.M24 = 1.0f; B.M31 = 0.0f; B.M32 = 3.0f; B.M33 = 5.0f; B.M34 = 1.0f; B.M41 = 2.0f; B.M42 = 1.0f; B.M43 = 2.0f; B.M44 = 1.0f; return A * B; } To trigger the methods that calculate the matrix product and display the output, replace the line DrawFonts(gameTime); inside Draw() with the following: DrawMatrix(MultiplyMatrix()); When you run this code, the product matrix will appear in the window: 5.00 4.00 10.00 3.00 0.00 0.00 0.00 0.00 CHAPTER 16 Matrices MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 252 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 This result verifies that the code,C=A*B(where A, B, and C are Matrix ob- jects), generates the same product as shown in the lengthy manual calculation. Matrix Multiplication Example: 4×4 Matrix * 4×4 Matrix This next example demonstrates how to multiply a 4×4 matrix by a 4×4 matrix. Knowing how to do this by hand is very useful because all of the transformations you have been implementing in your XNA code involve multiplying 4×4 matrices by 4×4 matrices. You will first see how the multiplication can be performed manually, and then how you can do it in code. Manual Calculation For this case, the following two matrices, A and B, are to be multiplied: A X B = | 2 1 0 0 | X | 2 1 3 1 | |-1 -2 0 0 | | 1 2 4 1 | | 3 1 0 0 | | 0 3 5 1 | |-3 2 2 0 | | 2 1 2 1 | When you’re calculating the product of a 4× 4 matrix by a 4× 4 matrix, the for- mula to multiply the rows of matrix A by the columns of matrix B is for(r=1; r<=4; r++) for(c=1; c<=4;c++) C rc =A 1 *B 1c + A 2 *B 2c + A 3 *B 3c + A 4 *B 4c When the formula is implemented by hand, the calculation looks like this: |( 2*2 + 1*1 ( 2*1 + 1*2 ( 2*3 + 1*4 ( 2*1 + 1*1 |+ 0*0 + 0*2) + 0*3 + 0*1) + 0*5 + 0*2) + 0*1 + 0*1) |(-1*2 - 2*1 (-1*1 - 2*2 (-1*3 - 2*4 (-1*1 - 2*1 |+ 0*0 + 0*2) + 0*3 + 0*1) + 0*5 + 0*2) + 0*1 + 0*1) |( 3*2 + 1*1 ( 3*1 + 1*2 ( 3*3 + 1*4 ( 3*1 + 1*1 |+ 0*0 + 0*2) + 0*3 + 0*1) + 0*5 + 0*2) + 0*1 + 0*1) |(-3*2 + 2*1 (-3*1 + 2*2 (-3*3 + 2*4 (-3*1 + 2*1 |+ 2*0 + 0*2) + 2*3 + 0*1) + 2*5 + 0*2) + 2*1 + 0*1) = 253 | 5 4 10 3 | |-4 -5 -11 -3 | | 7 5 13 4 | |-4 7 9 1 | Calculation in Code After performing the long-winded manual calculation, you can appreciate the simplicity of being able to compute the same result with the instruc- tion C = A * B. Using the code solution from the previous example, in MultiplyMatrix(),re- place the instructions that set the individual cell values for matrix A with the follow- ing version (matrix B remains the same as the previous example, so no changes are required to it): A.M11 = 2.0f; A.M12 = 1.0f; A.M13 = 0.0f; A.M14 = 0.0f; A.M21 =-1.0f; A.M22 =-2.0f; A.M23 = 0.0f; A.M24 = 0.0f; A.M31 = 3.0f; A.M32 = 1.0f; A.M33 = 0.0f; A.M34 = 0.0f; A.M41 =-3.0f; A.M42 = 2.0f; A.M43 = 2.0f; A.M44 = 0.0f; When you run the code, you will see the result does indeed match the manual cal- culation: | 5.00 4.00 10.00 3.00 | |-4.00 -5.00 -11.00 -3.00 | | 7.00 5.00 13.00 4.00 | |-4.00 7.00 9.00 1.00 | At this point, we can say when multiplying a 4×4 matrix by a 4×4 matrix that the manual calculation can be executed in one line with the following instruction: Matrix C = A * B T RANSFORMATION MATRICES As mentioned earlier in this chapter, when drawing primitive shapes and 3D models, you use matrices to transform sets of vertices. Through the study of linear algebra, specific matrices have been defined to scale, rotate, and translate sets of vertices. In Chapter 7, the I.S.R.O.T. (Identity, Scale, Revolve, Orbit [translation and rotation], Translate) sequence of matrices is used to ensure balanced transformations. The same logic applies when you are using transformation matrices that have been cre- ated manually. If the matrices are multiplied in an incorrect order, the transforma- tions will also be incorrect. CHAPTER 16 Matrices When matrix calculations are performed in XNA, they are applied using the Right Hand Rule perspective, which was explained in Chapter 7. This chapter applies the transformation matrices from a Right Hand Rule perspective to suit the XNA frame- work. When you perform transformations on an object, the data matrix containing the X, Y, Z, and W coordinates is located on the left of the multiplication operator. The transformation matrix is located on the right. Translation Matrix Translation matrices store lateral transformations along the X, Y, and Z planes. Here is the format for the translation matrix: | 1 0 0 0 | | 0 1 0 0 | | 0 0 1 0 | | X Y Z 1 | When you are presented with a 4×4 matrix with 1s along the diagonal, values for X, Y, Z at the bottom, and 0s elsewhere, you can conclude the matrix will perform a translation of X units along the X plane, Y units along the Y plane, and Z units along the Z plane. Handling the W Component When a vector representing the X, Y, and Z coordinates of an object is transformed using a translation matrix, the W component in the fourth column of the data matrix must be set to 1. Failing to set all values in the fourth column of the data matrix to 1 will lead to inaccurate translations. Translation Matrix Example Imagine that the vertex (X=2, Y=1, Z=0) is transformed by the matrix on the right. The vector data matrix is located on the left. Note that the fourth column represent- ing the W component is set to 1. The translation matrix for the format described here must be located on the right side of the operator for the calculation to work properly. | 2 1 0 1 | X | 1 0 0 0 | | 0 1 0 0 | | 0 0 1 0 | | 3 5 0 1 | MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 254 255 Viewing this vertex and translation matrix gives you enough information to deter- mine that the vertex with the coordinates X=2, Y=1, and Z=0 will be transformed by three units in the positive X direction, and five units in the positive Y direction. If this is correct, the product of the vertex and translation matrix should move the vertex to X=5, Y=6, and Z=0. Figure 16-1 shows the coordinate in its original position before the predicted translation (on the left) and after the predicted translation (on the right). To verify the prediction, you can try this calculation in code. To set up the data matrix, replace the code that initializes the cells in matrix A with this revision to ini- tialize the vector data. The remaining rows will take on the default of 0 in each cell. // store vector in first row - all other cells equal 0 by default A.M11 = 2.0f; A.M12 = 1.0f; A.M13 = 0.0f; A.M14 = 1.0f; Next, to set up the translation matrix, replace the code that assigns matrix B with this revision: B.M11 = 1.0f; B.M12 = 0.0f; B.M13 = 0.0f; B.M14 = 0.0f; B.M21 = 0.0f; B.M22 = 1.0f; B.M23 = 0.0f; B.M24 = 0.0f; B.M31 = 0.0f; B.M32 = 0.0f; B.M33 = 1.0f; B.M34 = 0.0f; B.M41 = 3.0f; B.M42 = 5.0f; B.M43 = 0.0f; B.M44 = 1.0f; If you run this code, the output that appears in the window matches the prediction that the new coordinates are X=5, Y=6, and Z=0: 5.00 6.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 CHAPTER 16 Matrices FIGURE 16-1 Translating an object with the translation matrix MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 256 The translation moved the original vertex three units in the positive X direction, and five units in the positive Y direction. Translation Matrix Example Using the CreateTranslation() Method Since Chapter 7, we have used the method CreateTranslation(float x, float y, float z) to automatically generate the translation matrix. This method actually generates a translation matrix that is identical to the translation ma- trix we just created manually. If you replace the code inside MultiplyMatrix() that assigns cell values to matrix B with the following instruction, you will generate an identical matrix: B = Matrix.CreateTranslation(3.0f, 5.0f, 0.0f); Therefore, when you compile and run the code, the product matrix will also be identical. Scaling Matrix Scaling matrices are used any time an object needs to be resized. You will often need to scale your 3D models because modeling tools usually generate them in a size that is different from the size needed for your game project. The following matrix represents a standard matrix for performing scaling operations. At a glance, this scaling matrix contains information to expand or shrink an object in the X, Y, and Z planes. The X, Y, and Z scaling factors are set on the diagonal down from the top left to the bottom right. The digit, one, is needed in the bottom-right corner, and zeros are placed else- where to make this matrix a scaling matrix. X 0 0 0 0 Y 0 0 0 0 Z 0 0 0 0 1 Scaling Matrix Example In this example, you will use a scaling matrix to double the size of a triangle. A trian- gle is represented with the matrix containing the triangle vertices on the left. The ver- tex coordinates used to build the triangle are ( (0, 0, 0), (1, 4, 0), (4, 2, 0) ). The scaling matrix that doubles the size of the triangle is on the right. In the first three rows of the data matrix on the left, the X, Y, and Z coordinates for the three triangle vertices are 257 stored. One triangle vertex is stored in each of the first three rows. When multiplying the triangle vertices by the scaling matrix (to double the size), you can use the follow- ing matrix equation: | 0 0 0 0 | X | 2 0 0 0 | | 1 4 0 0 | | 0 2 0 0 | | 4 2 0 0 | | 0 0 2 0 | | 0 0 0 0 | | 0 0 0 1 | By looking at the scaling matrix—and without performing any calculations—it is apparent that the size of the existing triangle is going to be doubled. In Figure 16-2, you can see that the size of the triangle has doubled when a vector set was trans- formed with the scaling matrix. Inside MultiplyMatrix(), replace the code that assigns values to the cells of matrix A with the following revision to initialize the data matrix for the triangle: A.M11 = 0.0f; A.M12 = 0.0f; A.M13 = 0.0f; A.M14 = 0.0f; A.M21 = 1.0f; A.M22 = 4.0f; A.M23 = 0.0f; A.M24 = 0.0f; A.M31 = 4.0f; A.M32 = 2.0f; A.M33 = 0.0f; A.M34 = 0.0f; A.M41 = 0.0f; A.M42 = 0.0f; A.M43 = 0.0f; A.M44 = 0.0f; CHAPTER 16 Matrices FIGURE 16-2 Before scaling and after scaling [...]... repositioned at the window center each frame, allowing the player to end the game with a keypress event is essential because she will not be able to click the close 275 Building a Graphics Engine Camera C H A P T E R 276 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE button in the top right of the window To enable the gamer to close the game application with either a Back button press on the controller or an... using the solution from the previous example To create a rotation matrix of π/4 radians about FIGURE 16-3 Rotation of a triangle using the X rotation matrix 259 Matrices C H A P T E R 260 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE the X axis, replace the instructions that initialize matrix B with the following version inside MultiplyMatrix(): float float B.M11 B.M21 B.M31 B.M41 sin = (float)Math.Sin(Math.PI... 0.0f; = cos; = 0.0f; B.M14 B.M24 B.M34 B.M44 FIGURE 16-4 Y axis rotation before and after the transformation matrix is applied = = = = 0.0f; 0.0f; 0.0f; 0.0f; 261 Matrices C H A P T E R 262 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE When you run this program, the product matrix stores the triangle’s new coordinates after they are rotated by π/4 units around the Y axis (see Figure 16-4) Y Axis Rotation... not actually perform a transformation However, the identity matrix is included in the recommended I.S.R.O.T sequence of transformations to ensure that the World matrix is initialized 264 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE properly when no other transformation matrix is applied By default, an identity matrix is used in the World matrix to initialize it The World matrix is explained in more detail... visibility for the camera A large projection creates a wide-angle lens Another way to say this is that the Projection matrix describes the 269 Building a Graphics Engine Camera C H A P T E R 270 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE frustum, which is the cone-shaped view seen by the camera The frustum has front and back boundaries on the Z axis known as the near clip plane and the far clip plane, respectively... you need to implement a camera that can be used for first-person shooter games, racing games, and many others In fact, the code explained here is the same code used in the MGHWinBaseCode and MGH360BaseCode base code projects You can begin with either the Windows Game project or Xbox 360 Game project template to generate your game application shell The camera you add will move and strafe with arrow... set to 0.9f to elevate the camera position and view above the ground: public Camera(){ position = new Vector3(0.0f, 0.9f, 0.0f); 271 Building a Graphics Engine Camera C H A P T E R 272 MICROSOFT view up XNA GAME STUDIO CREATOR’S GUIDE = new Vector3(0.0f, 0.9f,-0.5f); = new Vector3(0.0f, 1.0f, 0.0f); } In the camera class, SetFrameInterval() provides an interface for setting a scaled measure based on... (float)windowWidth/(float)windowHeight, 0.005f, 1000.0f); } Initializing the Camera from Your Game Class To reference the camera in your game class, include the camera’s namespace, CameraViewer, in your Game1 .cs file: using CameraViewer; The camera is instantiated from the game class with the following line: private Camera cam = new Camera(); 1 7 Adding a camera to the game template helps to enable 3D graphics, but some extra setup... point is the View, which is set from each frame from the Update() method and controls the camera’s current direction: cam.SetView(); 273 Building a Graphics Engine Camera C H A P T E R 274 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE Moving and Strafing Once you have defined the basic camera, you can add methods to enable the viewer to move forward, backward, or sideways (strafing) in the 3D world Updating...258 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE Next, replace the code that initializes matrix B with this version to initialize a scaling matrix: B.M11 B.M21 B.M31 B.M41 = = = = 2.0f; 0.0f; 0.0f; 0.0f; B.M12 B.M22 B.M32 . pixel safeArea.Top+(float)i*height), Color.Yellow); // color MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 250 251 } spriteBatch.End(); } When you open the solution, you must add the MultiplyMatrix() method to the game class so it can. appear in the window: 5.00 4.00 10.00 3.00 0.00 0.00 0.00 0.00 CHAPTER 16 Matrices MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 252 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 This result verifies that. calculation to work properly. | 2 1 0 1 | X | 1 0 0 0 | | 0 1 0 0 | | 0 0 1 0 | | 3 5 0 1 | MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 254 255 Viewing this vertex and translation matrix gives you enough