GameDev.netThe World of 3-D Graphics Part 2: Vectors and Planes

The World of 3-D Graphics ## Prelude to a Greater UnderstandingI got a lot of feedback from the first article, much of it complaining about its simplicity. Well, soon you’ll be screaming at me to go back to the simple stuff. This time, I’ll be discussing basic vector math and we will also be taking a look at planes. The following information is the kind of stuff that you need to understand if you wish to succeed in the world of 3-D graphics. So listen up well, and soon you’ll be doing all kinds of neat things. ## What is a Vector?When I discussed points I mentioned that a vector consisted of similar properties to a point. Well here is the point structure again. struct Point { float x; float y; float z; }; And introducing our vector structure… struct Vector { float x; float y; float z; }; "Holy Jamoly", I can hear you say, "They look exactly the same". Well, yes that is true, but where they differ is in what they represent mathematically. Remember a point is used to reference a particular position in our coordinate system. Well rather than position, a vector represents two new concepts: When we speak of magnitude we speak of length, and direction obviously means which way the vector is pointing.
Imagine that each axis on this coordinate system is 5.0 units in length. You can see our vector < 2.0 ## How long is your Vector?In many vector operations which are performed, prior knowledge of the length of the vector is required. To find the length of a vector you take the square root of the sum of squares of each vector component as shown below.
Note that our vector V is denoted using the inline float Length( Vector &v ) { return( sqrtf( (v.x*v.x) + (v.y*v.y) + (v.z*v.z) ) ) } Using the vector in
## Normalized VectorAlso known as the
So we have our vector V with its values described above. We calculate the magnitude of the vector and we find that its length is 7.0. Following that we divide each component by the magnitude. If we calculate the length of the vector again we now find that it is equal to 1.0, the very value which makes it a normal vector. Remember that although the vector's length may now be equal to 1.0 its direction is still the same. Here is a way we can do it in code. inline Vector Normalize( Vector &v ) { float temp = 1/Length( v ); v.x *= temp; v.y *= temp; v.z *= temp; return( v ); } Notice how we cached the division. That’s a nice optimization because multiplication is faster than division. ## Vector OperationsWe can perform operations on vectors like we would on our everyday numbers such as addition, subtraction, and multiplication (though multiplication has two different interpretations). ## Addition
inline Vector AddVect( Vector &v1, Vector &v2 ) { Vector v; v.x = v1.x + v2.x; v.y = v1.y + v2.y; v.z = v1.z + v2.z; return( v ); } ## Subtraction
inline Vector SubVect( Vector &v1, Vector &v2 ) { Vector v; v.x = v1.x - v2.x; v.y = v1.y - v2.y; v.z = v1.z - v2.z; return( v ); } ## Multiplication with a Scalar NumberTo increase the length of a vector we can multiply with a scalar number. inline Vector ScaleIncrease( Vector &v, float &s ) { v.x *= s; v.y *= s; v.z *= s; return( v ); } ## Division with a Scalar NumberTo decrease the length of a vector we can divide with a scalar number. inline Vector ScaleDecrease( Vector &v, float &s ) { v.x /= s; v.y /= s; v.z /= s; return( v ); } ## Dot ProductThe Dot Product is a vector operation which will return a scalar value (single number), which for unit vectors is equal to the cosine of the angle between the two input vectors (for non-unit vectors, it is equal to the length of each multiplied by the cosine, as shown in the equation below). We can represent the Dot Product equation with the ● symbol.
alternatively
In Figure 5, there are two vectors pointing in different directions. Where those vectors meet you can find the dot product. Before we do anything else let’s take a look at the dot product code. inline float DotProduct( Vector &v1, Vector &v2 ) { return( (v1.x*v2.x) + (v1.y*v2.y) + (v1.z*v2.z) ); } This seems to be a complex task, but it's actually quite simple in code. All we did was multiply each vector component together and sum the products. Our returned value is a scalar value - not a vector - and this is our dot product. It won’t take long in your exploration of 3-D graphics before you find yourself using the dot product frequently. Among other things, it is useful in backface culling, lighting and collision detection. ## Cross ProductAnother useful vector operation is the cross product. Unlike the dot product which returns a scalar value the cross product actually returns a vector. The vector which is returned is perpendicular to the two input vectors. inline Vector CrossProduct( Vector &v1, Vector &v2 ) { Vector v; v.x = ( v1.y * v2.z ) – ( v1.z * v2.y ); v.y = ( v1.z * v2.x ) – ( v1.x * v2.z ); v.z = ( v1.x * v2.y ) – ( v1.y * v2.x ); return( v ); } In 3D graphics, the most common use of the cross product is to calculate a polygon normal. Calculating the polygon normal can be great for backface culling and lighting. We do this by doing a cross product on two vectors that lie on the polygon's plane (more on planes in a sec).
## What is a Plane?A plane is like a huge piece of paper. Each triangle making up our models lies in its own plane.
The above equation describes our plane. The < a, b, c > triplet describes the normal of our plane. The normal is the vector which is perpendicular to all of the points which lie on the plane. We learned how to calculate the normal when we were learning about the cross product. The d component is a scalar value which represents the distance from the plane to the origin < 0
In this diagram, the normal points away from the origin, so the distance is negative. If the normal pointed toward the origin, the distance would be a positive value. Obviously if the plane goes through the origin then the distance would be equal to zero. ## Constructing a Plane// global variables Vector norm; float distance; void ConstructPlane( Vector &p0, Vector &p1, Vector &p2 ) { norm = CrossProduct( SubVect(p2 ,p1), SubVect( p0,p1) ); norm = Normalize(norm); distance = -DotProduct( norm, p1 ); } Not too complicated; all we are doing here is performing a cross product on the two vectors which are made up of the three points. We do this to find the normal and then we make it unit length. To find the distance we calculate the negative dot product of the normal with the point of your choice. ## Defining the location of a point in relation to a planeDefining the location of a point in relation to a plane is one of the most common operations we can do with planes. There are three possible cases when perfoming this operation. They are: front of the plane, back of the plane, and coplanar with the plane. So, how do we tell the difference between the front of the plane and the back of the plane? The front is defined as the side which the normal sticks out of, so obviously the back of the plane is the opposite side.
Looking at The returned value is the distance from the plane. Remember that if that value is equal to zero than we are indeed coplanar with the plane. ## ConclusionIf you have made it this far then well done. Compared to what we have ahead of us this stuff is relatively simple but those who haven’t studied vector math before may find it a little confronting. Don’t worry to much, once you start using this stuff more everything will fall into its place. Next time we dwelve into the mysteries of the matrix. Well I guess this is goodbye, I’ll see you next time. Love me? Hate me? Questions? Suggestions? How about you e-mail me here.
© 1999-2011 Gamedev.net. All rights reserved. |