Those who are new to 3D graphics might ask the question, "Do I need to know math to create 3D graphics?"The simple answer is "Yes, there is a level of mathematics that is required when you are working on a 3D game." Can you get by without knowing much? Absolutely, and we have seen many examples where people have created a 3D game but don’t necessarily understand how they are getting the results they see. This often leads to questions such as,"Why is my model orbiting around the camera when I wanted it to rotate on its axis like a planet?"
Without a doubt, having a better understanding of underlying mathematics leads you to be less confused, more quickly understand new concepts, and be more productive.
This section attempts to strike a balance of theory and practical use.The goal is to give you the higher level concepts that are used throughout 3D graphics without having to explain the details of how to do specific mathematical operations such as vector arithmetic or matrix multiplication. There are countless educational sources on these operations, and they are already implemented in the math types provided in XNA Game Studio.We spend our time focusing on what these operations mean geometrically and how they are used within 3D graphics.
Coordinate Systems
We already used one type of coordinate system, which were screen coordinates when drawing sprites on the screen. In screen coordinate space, there are two dimensions: one for each of the X and Y directions. In screen coordinates, the X direction increases in value from the left side of the screen to the right, and the Y increases in value from the top of the screen to the bottom.
There are two main types of 3D coordinate systems used in computer graphics.These two different types differ in direction from the positive Z points relative to the X and Y axes.The two types of coordinate systems are called right-handed and left-handed (see Figure 4.1). Both of these systems contain three directions for the X,Y, and Z axes.The three axes converge at a central point called the origin where their values equal 0. The values along each axis either gain or lower in value at regular intervals depending on whether you are moving in the positive or negative direction along that axis.
Figure 4.1 Left- and right-handed coordinate systems
To visualize these two different coordinate systems, let’s do a quick exercise. Take your right hand and make a fist. Turn your hand so your bent fingers face you and the top of your hand faces away from you. Now, extend your thumb. It should point directly to your right.Your thumb represents the positive X axis. Now extend your index finger, also known as your pointer finger, directly up in the air.This represents the positive Y direc-tion.Your hand should look like it is making a capital L now with your thumb facing right and representing the positive X axis and your index finger pointing upwards representing the positive Y axis. Finally, extend your middle finger and point it directly at your-self.Your middle finger represents the positive Z axis (see Figure 4.2).
Imagine lines that extend from the tips of all three of your fingers; they should be 90 degrees apart from each other forming right angles between themselves. Having each axis be at right angles from each other creates what is called an orthogonal coordinate system. In this case, you created a right-handed coordinate system. This is the coordinate system used by default in XNA Game Studio. In a right-handed coordinate system, the negative Z axis is used for the forward direction.
Figure 4.2 Right fist forming the right-handed coordinate system
Note
DirectX by default uses a left-handed coordinate system. The properties and methods in XNA Game Studio assume you are using a right-handed coordinate system. Some methods also provide a left-handed equivalent for those who want to use a left-handed system.
To visualize a left-handed system, follow the previous instruction except face your palm away from yourself but still make a capital L with your thumb and index finger for the positive X and Y axes. Now when you extend your middle finger to form the positive Z axis, notice that it now points away from you. In a left-handed coordinate system, the positive Z axis is used for the forward direction (see Figure 4.3).
Figure 4.3 Left fist forming the left-handed coordinate system
Note
Although we just stated that Z axis is used for the forward direction, this is not always true. In some 3D art creation packages, the Z axis actually represents the up direction. The good news is that this difference is accounted for when XNA Game Studio loads models from those specific 3D content packages.
Vectors in 3D Graphics
A vector is a mathematical geometric construct that consists of multidimensional values that provide a magnitude and direction. That sounded a little too much like a math class. You can think of vectors as a set of floating point values used to represent a point or direction in space. Use groups of vectors to represent the triangles that make up the geometry in your game.
"The Vector2 type, which contains two float values for X and Y is used to express the position to draw the sprites. XNA Game Studio also provides Vector3 and Vector4 types, which contain three and four components each.
XNA Game Studio uses free vectors. Free vectors are represented by a single set of components equal to the number of dimensions of the vector.This single set of components is able to express a direction and a magnitude. By contrast, in mathematics, another type of vector exists called a bounded vector, which is represented by two sets of components for both the start point and the end point. Because they are not often used in computer graphics, we focus on free vectors, which we call just "vectors."
What Units Are Vectors In?
Vectors are in whatever unit you want them to be in. The important rule is to be consistent throughout your game and even your art pipeline. If one artist creates buildings for your game and one unit equals a meter, and another artist creates your game characters with one unit equaling one inch, the buildings are going to look small or your characters are going to look big. If you are working on a team, it is helpful to decide on what one unit is equal to in your game.
If you are not able to author or export your art content yourself, the content pipeline scales your models for you given a scaling factor.
Vector4 the Four Dimensional Vector
As we mentioned, XNA Game Studio supports three types of vectors: Vector2, Vector3, and Vector4. Vector2 has two dimensions, so use it in 2D graphics. Vector3 has three dimensions, and is used it in 3D graphics.What should Vector4 be used in?
A Vector4 like the Vector3 type contains the X, Y, and Z values.The fourth component, called the homogeneous component and represented by the W property, is not used for space time manipulation unfortunately. The fourth component is required when multiplying the vector by a matrix, which has four rows of values. Matrices and vector multiplication are discussed later in this topic.
Point Versus Direction and Magnitude
When working with Vector3 and Vector4 values, they can represent a 3D point in space or a direction with a magnitude.When you use a vector as the vertex position of a triangle, it represents a point in space.When a vector is used to store the velocity of an object, it represents a direction and a magnitude.The magnitude of a vector is also commonly referred to as the length of the vector and can be accessed using the Length property of all of the vector types.
It is often useful to have a vector that represents a direction and magnitude to have a length of 1.This type of vector is called a unit vector. Unit vectors have nice mathematical properties in that they simplify many of the equations used with vectors so that their operations can be faster, which is important when creating real-time graphics in games. When you change a vector, so its direction stays the same but the length of the vector is set to one, it is called normalizing the vector.A Normalize method is provided for each of the vector types.
Vector Addition
When you add two vectors A and B together, you obtain a third vector C, which contains the addition of each of the vector components.Vector addition, like normal algebraic addition, is commutative meaning that A + B is equal to B + A.
Geometrically vector addition is described as moving the tail of the B vector, which is at the origin, to the head of the A vector, which is the value the A vector represents in space. The resulting vector C is the vector from the tail of A, which is the origin, to the head of B.
In Figure 4.4, vector A contains a value of { 2, 1 } and vector B contains a value of { 1, 3 }.The resulting vector C contains the value { 3, 4 }.
Figure 4.4 Example of vector addition
If any of the components of the vector are negative, the values are added together in the same way. The resulting value can have negative components.
Vector Subtraction
When you subtract two vectors A and B from each other, you obtain a third vector C, which is the difference of each of the vector components.Vector subtraction is not commutative meaning that A — B is not equal to B — A.
Geometrically vector subtraction is described as moving the head of vector B to the head of the A vector.The resulting vector C is formed from the tail of A, which is at the origin, to the tail of B.
In Figure 4.5, vector A contains a value of { 3, 4 } and vector B contains a value of { 1, 3 }.The resulting vector C contains the value { 2, 1 }.
Figure 4.5 Example of vector subtraction Vector Scalar Multiplication
Vectors can be multiplied by a single number called a scalar. This scalar value is multiplied against each component to produce a new vector with the same direction but whose length has been multiplied by the scalar.
Geometrically the multiplication of a vector by a scalar can be described as taking the original vector and stretching or shrinking the length by the scalar value.
In Figure 4.6, vector A has a value of { 1,2 }.When multiplied by the scalar of 2, the new vector S has a value of { 2, 4 }.
Figure 4.6 Example of vector scalar multiplication
Vector Negation
To negate a vector, each of the component’s signs are changed to the opposite. Positive components become negative and negative components become positive. This is the same as multiplying the vector by a value of negative one.The negation of a vector is often written —A, where A is the vector name. Each of the vector types contains a method called Negate, which returns the negation of the given vector.
Geometrically the negation of a vector represents a vector in the opposite direction with the same length.
In Figure 4.7, vector A has a value of { 2, -1 }.When negated, it produces vector N, which has the value { -2, 1 }.
Vector Dot Product
The dot product, also called the scalar product, creates a scalar value from multiplying each of the vector components with each other and adding the results together.The dot product is written in the form A • B, pronounced as A dot B. The resulting scalar value is equal to the cosine of the angle times the length of A times the length of B.As we mentioned before, using normalized vectors simplifies some linear algebra equations, and this is one of them.To determine the angle between two vectors, first normalize each of the vectors.
Figure 4.7 Example of vector negation
Then, take the dot product to return the cosine of the angle. Use the arccosine to find the angle value in radians.
Geometrically you can think of the dot product of two vectors A and B as the length of vector A in the direction of vector B. Because the vector dot product is commutative, it has the same value as the length of vector B in the direction of vector A.This of this as one vector casting a shadow onto the other vector.
In Figure 4.8, the dot product A • B is both a scalar value related to the angle between the vectors as well as the length of vector A in the direction of vector B.
Vector Cross Product
The vector cross product of vectors A and B produce a resulting vector C that is perpendicular to the plane that both A and B are located on. The cross product is commonly written as A X B pronounced A cross B. The cross product is helpful when building ortho-normalized coordinate spaces. As we discussed, 3D coordinate spaces contain three unit vectors for the X,Y, and Z axis. Each of these unit vectors can be created by taking the cross product of the other two axes.The Z axis is created from the result of X cross Y.Y from Z cross X. X from Y cross Z.The cross product is not commutative nor is it associative, so A X B is not equal to B X A. Taking the cross product of B X A produces a perpendicular vector that is the negation of A X B.
In Figure 4.9, notice that vectors A X B produces a perpendicular vector C while B X A produces a vector equal to —C.
Figure 4.8 Example of vector dot product
Figure 4.9 Example of vector cross product Vectors in XNA Game Studio
The vector types in XNA Game Studio provide a number of helpful properties and methods to perform the calculations we have been discussing and more that we cover throughout this topic.Tables 4.1, 4.2, and 4.3 contain the fields, properties, and methods of the Vector3 type.The Vector2 and Vector4 types have similar fields, properties, and methods.
Table 4.1 Fields of Vector3
Field |
Type |
Description |
X |
float |
The X component of the vector |
Y |
float |
The Y component of the vector |
Z |
float |
The Z component of the vector |
Table 4.2 Properties of Vector3
Property |
Type |
Description |
UnitX |
Vector3 |
Static property that returns a vector with the values { 1, 0, 0 } |
UnitY |
Vector3 |
Static property that returns a vector with the values { 0, 1, 0 } |
UnitZ |
Vector3 |
Static property that returns a vector with the values { 0, 0,1 } |
Right |
Vector3 |
Static property that returns a unit vector pointing in the right direction { 1, 0, 0 } |
Left |
Vector3 |
Static property that returns a unit vector pointing in the left direction { -1, 0, 0 } |
Up |
Vector3 |
Static property that returns a unit vector pointing in the up direction { 0, 1, 0 } |
Down |
Vector3 |
Static property that returns a unit vector pointing in the down direction { 0,-1, 0 } |
Forward |
Vector3 |
Static property that returns a unit vector pointing in the forward direction { 0, 0, -1 } |
Backward |
Vector3 |
Static property that returns a unit vector pointing in the backward direction { 0, 0, 1 } |
One |
Vector3 |
Static property that returns a vector with the values { 1, 1,1 } |
Zero |
Vector3 |
Static property that returns a vector with the values { 0, 0, 0 } |
Table 4.3 Abbreviated Table of Vector3 Methods
Method |
Description |
Add |
Returns the additions of two vectors. |
Subtract |
Returns the subtraction of two vectors. |
Negate |
Returns the negation of two vectors. |
Dot |
Returns the scalar result from the dot product of two vectors. |
Cross |
Returns a perpendicular vector that is the cross product of two |
vectors. |
Table 4.3 Abbreviated Table of Vector3 Methods
Method |
Description |
Multiply |
Multiplies each component of a vector by a scalar value or another vector. |
Divide |
Divides each component of a vector by a scalar value or another vector. |
Normalize |
Normalizes a vector to have a unit length of one with the same direction as the starting vector. |
Length |
Returns the length of the vector. |
LengthSquared |
Returns the length of the vector squared. It is a less expensive operation to calculate the length squared of a vector. Use for relative comparisons. |
Distance |
Returns the distance between two vectors. |
DistanceSquared |
Returns the distance between two vectors squared. It is a less expensive operation to calculate the distance squared. Use for relative comparisons. |
Min |
Returns a vector whose components are the smallest from each of the given vectors. |
Max |
Returns a vector whose components are the largest from each of the given vectors. |
Transform |
Transforms a vector that represents a point by a matrix. |
TransfromNormal |
Transforms a vector that represents a normal by a matrix. |
Note
Many of the math methods provided in XNA Game Studio provide overloads, which take the parameters as references and return the result as an out parameter. Using these versions of the methods can save the overhead of many copies of the structures passed to the method. Use these versions in your time-critical sections of your game where you have performance problems.