420 114 14MB
English Pages 626 [413] Year 2006
1
Introduction to 3D Game Programming with DirectX 9.0c—A Shader Approach Frank D. Luna Wordware Publishing, Inc. Library of Congress Cataloging-in-Publication Data Luna, Frank D. Introduction to 3D game programming with DirectX 9.0c : a shader approach / by Frank D. Luna. p. cm. Includes index. ISBN-13: 978-1-59822-016-2 ISBN-10:1-59822-016-0 (pbk.) 1. Computer games--Programming 2. DirectX. I. Title. QA76.76.C672L833 2006 794.8'1526--dc22 2006006448 © 2006, Wordware Publishing, Inc. All Rights Reserved 2320 Los Rios Boulevard Plano, Texas 75074 No part of this book may be reproduced in any form or by any means without permission in writing from Wordware Publishing, Inc. Printed in the United States of America ISBN-13: 978-1-59822-016-2 ISBN-10: 1-59822-016-0 10 9 8 7 6 5 4 3 2 1 0605 DirectX is a registered trademark of Microsoft Corporation in the United States and other countries. Other brand names and product names mentioned in this book are trademarks or service marks of their respective companies. Any omission or misuse (of any kind) of service marks or trademarks should not be regarded as intent to infringe on the property of others. The publisher recognizes and respects all marks used by companies, manufacturers, and developers as a means to distinguish their products. This book is sold as is, without warranty of any kind, either express or implied, respecting the contents of this book and any disks or programs that may accompany it, including but not limited to implied warranties for the book's quality, performance, merchantability, or fitness for any particular purpose. Neither Wordware Publishing, Inc. nor its dealers or distributors shall be liable to the purchaser or any other person or entity with respect to any liability, loss, or damage caused or alleged to have been caused directly or indirectly by this book. All inquiries for volume purchases of this book should be addressed to Wordware Publishing, Inc., at the above address. Telephone inquiries may be made by calling: (972) 423-0090 To my parents, Frank and Kathryn Acknowledgments I would like to thank Rod Lopez, Jim Leiterman, Hanley Leung, Rick Falck, Tybon Wu, Tuomas Sandroos, and Eric Sandegren for putting in the time to review this book for both accuracy and improvements. I also want to thank Dale E. La Force, Adam Hault, Gary Simmons, James Lambers, and William Chin for their assistance. Lastly, I want to thank the staff at Wordware Publishing, in particular, Wes Beckwith, Beth Kohler, Martha McCuller, Denise McEvoy, and Alan McCuller.
2
Introduction Overview This book presents an introduction to programming interactive computer graphics, with an emphasis on game development, using real-time shaders with DirectX 9.0c. It teaches the fundamentals of Direct3D and shader programming, after which the reader will be prepared to go on and learn more advanced techniques. The book is divided into three main parts. Part I explains the mathematical tools that will be used throughout this book. Part II shows how to implement elementary 3D techniques, such as defining 3D geometry, lighting, texturing, alpha blending, and stenciling, using shaders and the HLSL. Part III is largely about applying Direct3D to implement a variety of interesting techniques and special effects, such as working with meshes, character animation, terrain rendering, picking, particle systems, environment mapping, normal mapping, and rendering to textures. For the beginner, this book is best read front to back. The chapters have been organized so that the difficulty increases progressively with each chapter. In this way, there are no sudden jumps in complexity that leave the reader lost. In general, for a particular chapter, we will use the techniques and concepts previously developed. Therefore, it is important that you have mastered the material of a chapter before continuing. Readers who are experienced Direct3D users can pick the chapters of interest. Finally, you may be wondering what kinds of games you can develop after reading this book. The answer to that question is best obtained by skimming through the book and seeing the types of applications that are developed. From that you should be able to visualize the types of games that can be developed based on the techniques taught in this book and some of your own ingenuity.
3
Changes from an Earlier Version This update to the author's Introduction to 3D Game Programming with DirectX 9.0 has been rewritten almost from scratch. This book largely abandons the fixed pipeline used in the earlier version to give a complete programmable, or shader, approach. From Chapter 8 onward, we are transforming, lighting, and coloring vertices and pixels in vertex and pixel shaders. This significant revision in approach reflects the fact that the fixed pipeline will not exist in DirectX 10. Another key feature is the inclusion of end of chapter exercises. The exercises serve three purposes: first, to test the reader's understanding of each chapter's contents; second, to provide the reader with Direct3D programming experience; and third, to extend the chapter's topics by asking the reader to investigate new ideas on his or her own. In many cases, the exercises are not of the "plug and chug" type, but require the reader to determine how to apply the chapter's topics to the particular assignment. Readers are encouraged to complete chapter exercises before moving on to the next chapter.
4
Intended Audience This book was designed with the following three audiences in mind: Intermediate level C++ programmers who would like an introduction to 3D programming using the latest iteration of Direct3D — Direct3D 9.0. 3D programmers experienced with an API other than DirectX (e.g., OpenGL) who would like an introduction to Direct3D 9.0. Experienced fixed-function Direct3D programmers who would like to take a shader approach.
5
Prerequisites It should be emphasized that this is an introduction to Direct3D, shader, and game programming; it is not an introduction to general computer programming. The reader should satisfy the following prerequisites: General knowledge of high school mathematics: algebra, trigonometry, and (mathematical) functions, for example. Competent with Visual Studio: should know how to create projects, add files, and specify external libraries to link, for example. Intermediate C++ and data structure skills: comfortable with pointers, arrays, operator overloading, linked lists, inheritance and polymorphism, for example. We also use a small subset of the STL, in particular, std::string, std::vector, and std::list. Familiarity with Windows programming with the Win32 API is helpful but not required; we provide a Win32 primer in Appendix A.
6
Required Development Tools and Recommended Hardware Officially, Microsoft's DirectX 9.0 now only supports versions of Visual Studio 7.0 (i.e., Visual Studio .NET 2002) or higher. In addition, to program DirectX 9.0 applications, you will need the DirectX 9.0 SDK; the latest version can be downloaded from http://msdn.microsoft.com/directx/sdk/. Once downloaded, follow the instructions given by the installation wizard. This book's demo programs require DirectX 9.0-capable hardware that supports vertex and pixel shader versions 2.0. At the time of this book's publication, low-end video cards supporting these requirements are available for about $50 (e.g., Radeon 9600, Geforce FX 5500). Online
Step-by-step instructions for setting up a DirectX project in Visual Studio .NET 2002 and Visual Studio .NET 2005 are provided on this book's website (www.moon-labs.com) and the publisher's website (www.wordware.com/files/dx9c).
7
Use of the D3DX Library Since version 7.0, DirectX has shipped with the D3DX (Direct3D Extension) library. This library provides a set of functions, classes, and interfaces that simplify common 3D graphics-related operations, such as math operations, texture and image operations, mesh operations, and shader operations (e.g., compiling and assembling). That is to say, D3DX contains many features that would be a chore to implement on your own. We use the D3DX library throughout this book because it allows us to focus on more interesting material. For instance, we would rather not spend pages explaining how to load various image formats (such as .bmps and .jpegs) into a Direct3D texture interface when we can do it in a single call to the D3DX function D3DXCeateTextureFromFile. In other words, D3DX makes us more productive and lets us focus more on actual content rather than spending time reinventing the wheel. Other reasons to use D3DX: D3DX is general and can be used with a wide range of different types of 3D applications. D3DX is fast, at least as fast as general functionality can be. Other developers use D3DX; therefore, you will most likely encounter code that uses D3DX. Consequently, whether you choose to use D3DX or not, you should become familiar with it so that you can read code that uses it. D3DX already exists and has been thoroughly tested. Furthermore, it becomes more improved and feature rich with each iteration of DirectX.
8
Using the DirectX SDK Documentation and SDK Samples Direct3D is a huge API and we cannot hope to cover all of its details in this one book. Therefore, to obtain extended information it is imperative that you learn how to use the DirectX SDK documentation. You can launch the C++ DirectX online documentation by executing the DirectX9_c file in the \DirectX SDK\Documentation\DirectX9 directory, where DirectX SDK is the directory to which you installed DirectX. The DirectX documentation covers just about every part of the DirectX API; therefore, it is very useful as a reference, but because the documentation doesn't go into much depth and assumes some previous knowledge, it isn't the best learning tool. However, it does get better and better with every new DirectX version released. As said, the documentation is primarily useful as a reference. Suppose you come across a DirectX-related type or function that you would like more information on (e.g., D3DXMatrixInverse). You simply do a search in the documentation index and you get a description of the object type or, in this case, function, as shown in Figure 1.
Figure 1: The C++ SDK documentation viewer. Note In this book we may direct you to the documentation for further details from time to time. The SDK documentation also contains some introductory tutorials at the URL \directx9_c.chm::/dx9_graphics_tutorials_and_samples.htm. These tutorials correspond to some of the topics in the first part of this book. We recommend that you study these tutorials at the same time you read through Part I so that you can get alternative explanations and examples. We would also like to point out the available Direct3D sample programs that ship with the DirectX SDK. The C++ Direct3D samples are located in the DirectX SDK\C++\Direct3D directory. Each sample illustrates how to implement a particular effect in Direct3D. These samples are fairly advanced for a beginning graphics programmer, but by the end of this book you should be ready to study them. Examination of the samples is a good "next step" after finishing this book.
9
Clarity We want to emphasis that the program samples for this book were written with clarity in mind and not performance. Thus, many of the samples may be implemented inefficiently. Keep this in mind if you are using any of the sample code in your own projects, as you may wish to rework it for better efficiency.
10
Sample Programs and Online Supplements The website for this book (www.moon-labs.com) plays an integral part in getting the most out of this book. On the website you will find the complete source code and project files for every sample in this book. In many cases, DirectX programs are too large to fully embed in a textbook; therefore, we only embed relevant code fragments based on the ideas being shown. It is highly recommended that the reader study the corresponding demo code to see the program in its entirety. (We have aimed to make the demos small and focused for easy study.) As a general rule, the reader should be able to implement a chapter's demo(s) on his or her own after reading the chapter and spending some time studying the demo code. In fact, a good exercise is trying to implement the samples on your own using the book and sample code as a reference. In addition to sample programs, the website also contains a message board. We encourage readers to communicate with each other and post questions on topics they do not understand or need clarification on. In many cases, getting alternative perspectives and explanations on a concept shortens the time it takes to comprehend it. And lastly, the website will contain additional program samples and tutorials on topics that we could not fit into this book for one reason or another. The companion files can also be downloaded from www.wordware.com/files/dx9c.
11
Part I: Mathematical Prerequisites Chapter List Chapter 1: Vector Algebra Chapter 2: Matrix Algebra Chapter 3: Transformations and Planes
Part Overview Video games attempt to simulate a virtual world; however, computers, by their very nature, crunch numbers. Thus the problem of how to convey a world to a computer arises. The answer is to describe our worlds, and the interactions therein, completely mathematically. Consequently, mathematics plays a fundamental role in video game development. In this prerequisites part, we introduce the mathematical tools that will be used throughout this book. The emphasis is on vectors, coordinate systems, matrices, and transformations, as these tools are used in just about every sample program of this book. In addition to the mathematical explanations, a survey and demonstration of the relevant classes and functions from the D3DX math library are provided. Note that the topics covered here are only those essential to understanding the rest of this book; it is by no means a comprehensive treatment of video game mathematics, as entire books are devoted to this topic. For readers desiring a more complete reference to video game mathematics, we recommend [Verth04] and [Lengyel02]. Chapter 1, "Vector Algebra" Vectors are, perhaps, the most fundamental mathematical objects used in computer games. We use vectors to represent positions, displacements, directions, velocities, and forces, for example. In this chapter, we study vectors and the operations used to manipulate them. Chapter 2, "Matrix Algebra" Matrices provide an efficient and compact way of representing transformations. In this chapter, we become familiar with matrices and the operations defined on them. Chapter 3, "Transformations and Planes" This chapter examines three fundamental geometric transformations: scaling, rotation, and translation. We use these transformations to manipulate 3D objects in space. In addition, a brief primer on 3D planes is provided; planes are useful for dividing and sorting 3D space.
12
Chapter 1: Vector Algebra Overview Vectors play a crucial role in computer graphics, collision detection, and physical simulation, all of which are common components in contemporary video games. Our approach here is informal and practical; for a more theoretical development, see [Schneider03]. We emphasize the importance of vectors by noting that they are used in just about every demo program in this book. Objectives: To develop an understanding of vectors, their geometry, and the operations defined on them. To learn how we can convert the coordinates of points and vectors from one coordinate system to another. To find out how vectors can be used to analytically describe other geometric objects such as rays, lines, and line segments. To become familiar with a subset of classes and functions provided by the D3DX library that are used for vector mathematics.
13
1.1 Vectors A vector refers to a quantity that possesses both magnitude and direction. Quantities that possess both magnitude and direction are called vector-valued quantities. Examples of vector-valued quantities are forces (a force is applied in a particular direction with a certain strength — magnitude), displacements (the net direction and distance a particle moved), and velocities (speed and direction). Thus, vectors are used to represent forces, displacements, and velocities. In addition, we also use vectors to specify pure directions, such as the direction the player is looking in a 3D game, the direction a polygon is facing, the direction in which a ray of light travels, or the direction in which a ray of light reflects off a surface. A first step in characterizing a vector mathematically is geometrically: We graphically specify a vector by a directed line segment (see Figure 1.1), where the length denotes the magnitude of the vector and the aim denotes the direction of the vector. We note that the location in which we draw a vector is immaterial because changing the location does not change the magnitude or direction. Consequently, two vectors are equal if and only if they have the same length and point in the same direction. Thus, the vectors and shown in Figure 1.1 are actually equal, that is , because they have the same length and point in the same direction. In fact, because location is unimportant for vectors, we can always translate a vector without changing its meaning (since a translation changes neither length nor direction). Observe that we could translate hence their equality.
Figure 1.1: Vectors drawn on a 2D plane. Note other.
such that it completely overlaps with
(and conversely), thereby making them indistinguishable —
; since they point in the same direction and have the same length, they are translations of each
1.1.1 Vectors and Coordinate Systems We could now define useful geometric operations on vectors, which can then be used to solve problems involving vector-valued quantities. However, since the computer cannot work with vectors geometrically, we need to find a way of specifying vectors numerically instead. So what we do is introduce a 3D coordinate system in space, and translate all the vectors so that their tails coincide with the origin (Figure 1.2). Then we can identify a vector by specifying the coordinates of its head, and write
= (x, y, z) as shown in Figure 1.3. Now we can represent a vector with three floats in a computer program.
Figure 1.2: Because translate
and
have the same length and point in the same direction (they are parallel), we say
such that it completely coincides with
, and observe that we can
. When a vector's tail coincides with the origin, we say that it is in standard position.
14
Figure 1.3: A vector specified by coordinates relative to a coordinate system. Consider Figure 1.4, which shows a vector and two frames in space. (Note that we use the terms frame, frame of reference, space, and coordinate system to all mean the same thing in this book.) We can translate
so that it is in standard position in either of the two frames. Observe, however, that the coordinates of the
vector differ based on the frame relative to which the vector is described. In other words, the same vector frames.
Figure 1.4: The same vector
has a different coordinate representation for distinct
has different coordinates when described relative to different frames.
The idea is analogous to, say, temperature. Water boils at Celsius or Fahrenheit. The physical temperature of boiling water is the same no matter the scale (i.e., we can't lower the boiling point by picking a different scale), but we assign a different scalar number to the temperature based on the scale we use. Similarly, for a vector, its direction and magnitude, which are embedded in the directed line segment, do not change, only the coordinates of it change based on the frame of reference we use to describe it. For example, wind blows in a particular direction and at some speed. We can measure the wind speed and direction relative to different frames of reference. For each distinct frame, we record different measurements. Nevertheless, the measurements are describing the same vector; that is, the frame of reference we pick cannot physically change the direction in which the wind blows nor does it change the magnitude of the wind. This is important because it means whenever we identify a vector by coordinates, those coordinates are relative to some frame of reference. Often, we will utilize more than one frame of reference and, therefore, will need to keep track of which frame the coordinates of a vector are described relative to; additionally, we will need to know how to convert vector coordinates from one frame to another (§1.5 shows how this conversion is done). Note We see that both vectors and points can be described by coordinates (x, y, z) relative to a frame. However, they are not the same; a point represents a location in 3-space, whereas a vector represents a magnitude and direction.
1.1.2 Left-Handed Versus Right-Handed Coordinate Systems DirectSD uses a so-called left-handed coordinate system. If you take your left hand and aim your fingers down the positive x-axis, and then curl your fingers toward the positive y-axis, your thumb points roughly in the direction of the positive z-axis. Figure 1.5 illustrates the differences between left-handed and right-handed coordinate systems.
Figure 1.5: On the left we have a left-handed coordinate system. Observe that the positive z-axis goes into the page. On the right we have a right-handed coordinate system. Observe that the positive z-axis comes out of the page. Observe that for the right-handed coordinate system, if you take your right hand and aim your fingers down the positive x-axis, and then curl your fingers toward the positive y -axis, your thumb points roughly in the direction of the positive z-axis.
1.1.3 Basic Vector Operations We now define equality, addition, scalar multiplication, and subtraction on vectors using the coordinate representation.
Two vectors are equal if and only if their corresponding components are equal. Let only if u x = vx , u y = vy , and u z = vz .
= (u x , u y , u z ) and
= (vx , vy , vz ). Then
if and
15 We add vectors component wise; as such, it only makes sense to add vectors of the same dimension. Let Then
= (u x , u y , u z ) and
= (vx , vy , vz ).
.
We can multiply a scalar (i.e., a real number) and a vector, and the result is a vector. Let k be a scalar, and let ku y , ku z ). This is called scalar multiplication.
= (u x , u y , u z ), then
We define subtraction in terms of vector addition and scalar multiplication. That is,
= (ku x ,
.
Example 1.1
Let
= (1,2,3),
= (1,2,3),
= (3,0,-2), and k = 2. Then,
;
Clearly,
;
; = 2(3,0,-2) = (6,0,-4).
The difference in the third line illustrates a special vector, called the zero-vector, which has zeros for all of its components and is denoted by
.
Note When comparing floating-point numbers, care must be taken due to floating-point imprecision. Two floating-point numbers that we expect to be equal may differ slightly, and therefore we test to see if they are approximately equal. We do this by defining an EPSILON constant, which is a very small value we use as a "buffer." We say two values are approximately equal if their distance is less than EPSILON. In other words, EPSILON gives us some tolerance for floatingpoint imprecision. The following function illustrates how EPSILON can be used to test if two floating-point values are equal: const float EPSILON = 0.001f; bool Equals(float lhs, float rhs) { // if lhs == rhs their difference should be zero return fabs(lhs - rhs) < EPSILON ? true : false; }
Example 1.2 We'll illustrate this example with 2D vectors to make the drawings simpler. The ideas are the same as in 3D; we just work with one less component in 2D.
Let
. How do
and
compare geometrically? We note
= (-1, -1/2). Graphing both
and
(Figure 1.6a), we notice that is in the direction directly opposite of and its length is 1/2 that of . Thus, geometrically, negating a vector can be thought of as "flipping" its direction, and scalar multiplication can be thought of as scaling the length of the vector.
Let
) and
parallel translate
. Then
. Figure 1.6b shows what vector addition means geometrically: We
so that its tail coincides with the head of
. (Note that we could have just as well translated
. Then, the sum is the vector originating at the tail of
so that its tail coincided with the head of
, then
and ending at the head of would be the vector
originating at the tail of and ending at the head of .) Observe also that our rules of vector addition agree with what we would intuitively expect to happen physically when we add forces together to produce a net force: If we add two forces (vectors) in the same direction, we get another stronger force (longer vector) in that direction. If we add two forces (vectors) in opposition to each other, then we get a weaker net force (shorter vector).
Let
and
Essentially, the difference then
. Then
. Figure 1.6c shows what vector subtraction means geometrically.
gives us a vector aimed from the head of
gives us a vector aimed from the point
one point to another. Observe also that the length of
to the point
to the head of
. If we instead interpret
and
as points,
; this interpretation is important as we will often want the vector aimed from
is the distance from
to
.
16
Figure 1.6: (a) The geometric interpretation of scalar multiplication. (b) The geometric interpretation of vector addition. (c) The geometric interpretation of vector subtraction.
17
1.2 Length and Unit Vectors Geometrically, the magnitude of a vector is the length of the directed line segment. We denote the magnitude of a vector by double vertical bars (e.g.,
denotes
the magnitude of ). Now, given a vector = (x, y, z), we wish to compute its magnitude algebraically. The magnitude of a 3D vector can be computed by applying the Pythagorean theorem twice; see Figure 1.7.
Figure 1.7: The 3D length of a vector can be computed by applying the Pythagorean theorem twice.
First, we look at the triangle in the xz-plane with sides x, z, and hypotenuse a. From the Pythagorean theorem, we have
triangle with sides a, y, and hypotenuse
. Now look at the
. From the Pythagorean theorem again, we arrive at the following magnitude formula:
(1.1)
For some applications, we do not care about the length of the vector because we want to use a vector to represent a pure direction. For such direction-only vectors, we want the length of the vector to be exactly one. When we make a vector unit length, we say that we are normalizing the vector. We can normalize a vector by dividing each of its components by its magnitude: (1.2)
Example 1.3
Normalize the vector
To verify that
= (-1, 3, 4). We have
is indeed a unit vector, we compute its length:
. Thus,
18
1.3 The Dot Product The dot product is a form of vector multiplication that results in a scalar value; for this reason, it is sometimes referred to as the scalar product. Let u z ) and
= (u x , u y ,
= (vx , vy , vz ); then the dot product is defined as follows:
(1.3)
In words, the dot product is the sum of the products of the individual components. The dot product definition does not present an obvious geometric meaning. Using the law of cosines, we can find the relationship (1.4)
Equation 1.4 says that the dot product between two vectors is the cosine of the angle between them scaled by the vectors' magnitudes. Thus, if both are unit vectors, then
is the cosine of the angle between them (i.e.,
).
Equation 1.4 provides us with some useful geometric properties of the dot product: If
If
If
, then
, then
, then
(i.e., the vectors are orthogonal).
(i.e., the vectors are parallel) and both
(i.e., the vectors are parallel) and
and
and
point in opposite directions.
If
, then the angle θ between the two vectors is less than 90 degrees (i.e., the vectors make an acute angle).
If
, then the angle θ between the two vectors is greater than 90 degrees (i.e., the vectors make an obtuse angle).
Note The term "orthogonal" can be used as a synonym for "perpendicular." Example 1.4
Let
point in the same direction.
= (l, 2, 3) and
= (-4, 0, -1). Find the angle between
Applying Equvation 1.4 tells us that
We can solve for thera using the trig arccosine function:
Example 1.5
and
. First observe that
and
19 Consider Figure 1.8. Given
and the unit vector
Figure 1.8: The orthogonal projection of
First, observe from the figure that since
the orthogonal projection of
on
using the dot product.
.
is a unit vector, we have
; therefore,
We call
, find a formula for
. Thus we must determine k. Using trigonometry, we know that
. However, because
on
. If we interpret
as a force,
. If
is not of unit length, we can always normalize it first to make it unit length.
is a unit vector, we can say this in another way:
can be thought of as the portion of the force
that acts in the direction
20
1.4 The Cross Product The second form of multiplication vector math defines is the cross product. Unlike the dot product, which evaluates to a scalar, the cross product evaluates to another vector. Taking the cross product of two 3D vectors, is orthogonal to
, and
is orthogonal to
and
, yields another vector,
; see Figure 1.9. If
, that is mutually orthogonal to
= (u x , u y , u z ) and
and
. By that we mean
= (vx ,vy , vz ), then the cross product is computed like so:
(1.5)
Figure 1.9: The cross product of two 3D vectors,
and
hand and aim the fingers in the direction of the first vector points in the direction of
, yields another vector,
, that is mutually orthogonal to
, and then curl your fingers toward
and
. If you take your left
along an angle 0 = θ = p , then your thumb roughly
; this is called the left-hand-thumb rule.
Example 1.6
Let to
= (2, 1, 3) and
= (2, 0, 0). Compute
and
, and then verify that
is orthogonal to
and that
is orthogonal
. Applying formula 1.5 we have,
and
This result makes one thing clear, generally speaking:
Therefore, we say that the cross product is anti-commutative. In fact, it can be
shown that . You can determine the vector returned by the cross product by the left-hand-thumb rule. If you curve the fingers of your left hand from the direction of the first vector toward the second vector (always take the path with the smallest angle), your thumb points in the direction of the returned vector, as shown in Figure 1.9.
To show that is orthogonal to orthogonal). Because
and that
is orthogonal to
, we recall from §1.3 that if
and
we conclude that
is orthogonal to
and that
is orthogonal to
.
, then
(i.e., the vectors are
21
1.5 Change of Frame Suppose that the scalar 100° C represents the temperature of boiling water relative to the Celsius scale. How do we describe the same temperature of boiling water relative to the Fahrenheit scale? In other words, what is the scalar, relative to the Fahrenheit scale, that represents the temperature of boiling water? To make this conversion (or change of frame), we need to know how the Celsius and Fahrenheit scales relate. They are related as follows: Therefore, T F =
.
(100°)+32°=212°. That is, the temperature of boiling water is 212° Fahrenheit.
This simple example illustrates that we can convert a scalar k that describes some quantity relative to a frame A into a new scalar k' that describes the same quantity relative to a different frame B, provided that we know how frame A and B are related. In this section, we look at a similar problem, but instead of scalars, we are interested in how to convert vector coordinates from one frame to another.
1.5.1 Vectors
Consider Figure 1.10 in which we have two frames, A and B, and a vector, by coordinates relative to frame A, and let us write
. To avoid ambiguity, let us write when we are specifying
when we are specifying by coordinates relative to frame B. Now, suppose
we are given . How do we find In other words, given the coordinates identifying a vector relative to one frame, how do we find the coordinates that identify the same vector relative to a different frame?
Figure 1.10: Two frames, A and B, and a vector,
. The same vector
has different coordinates relative to the two frames.
First, because we are talking about vectors in which location does not matter, we translate the coordinate systems so that their origins coincide as shown in Figure 1.11. Now let and Then from Figure 1.11, we see that
be unit vectors relative to frame B, which aim, respectively, along the x- and y-axes of frame A.
22
Figure 1.11: The geometry of identifying
relative to frame B.
Note the relationship between the two frames that allowed us to do this conversion: The relationship was that we described the axes of frame A relative to frame B with the vectors
and
. Thus, if we are given
Generalizing to 3D, if = (x, y, z), then frame A relative to frame B.
and we know the vectors
and
, where
, then we can always find
,
, and
.
describe the x-, y-, and z-axes of
We call the process of converting the coordinates that describe a vector relative to a frame A into new coordinates that describe the same vector relative to frame B a change of frame or change of coordinates transformation. Note The vectors
,
, and
actually do not need to be unit vectors. If they are not, it means that the two coordinate systems also differ in scale (in
addition to orientation and position). For example, if frame A used meters and frame B used centimeters, then magnitudes of 100 centimeters since there are 100 centimeters per meter.
,
, and
would have
Note The coordinate system chosen is somewhat arbitrary; however, picking a convenient coordinate system can sometimes make a problem easier. In other words, the geometry might have simpler coordinates in one coordinate system and more complex coordinates in another. Moreover, it is sometimes useful to use multiple coordinate systems. For example, we may want an answer in coordinate system A, but the problem is solved more easily in coordinate system B. In this case, we convert from A to B, solve the problem in B, and then convert back to A to give the answer.
1.5.2 Points We can also use a vector to represent a 3D location in space; we call this a position vector or point. In this case, the location of the tip of the vector (when the vector is in standard position; see §1.1.1) is the characteristic of interest, not the direction and magnitude. Since location is important for points, we cannot just translate the coordinate systems like we did in the previous section; this makes the change of frame transformation for points slightly different.
If
represents a point
relative to frame A, how do we describe the same point relative to frame B? In other words, what is
From Figure 1.12, we see that
23
Figure 1.12: The geometry of identifying point
where
relative to frame B.
= (Ox , Oy ) describes the origin of frame A relative to frame B, and
frame B. In 3D, if
= (x, y, z), then
= (u x , u y ) and
= (vx , vy ) describe the x- and y-axes of frame A relative to .
24
1.6 Rays, Lines, and Segments Suppose a player in a game we are working on fires his gun at an enemy. How would we determine whether the bullet starting from a particular position and aimed in a direction hit the target? One approach would be to model the bullet with a ray and model the enemy with a bounding sphere. (A bounding sphere is simply a sphere that tightly surrounds an object, thus roughly approximating its volume.) Then mathematically we can determine whether the ray hit the sphere and where. In this section we learn how to model rays mathematically. A ray can be described with an origin and a direction, as shown in Figure 1.13. The parametric equation of a ray is:
Figure 1.13: A ray described by an origin to zero.
and direction
. We can generate points on the ray by plugging in scalars for t that are greater than or equal
where is the origin of the ray, is a vector specifying the direction of the ray (not necessarily of unit length), and t is the parameter. By plugging in different values for t we obtain different points on the ray. The parameter t must be in the interval [0, 8) to describe a ray. Values less than zero will generate points behind the ray (i.e., on the line that coincides with the ray). In fact, if we let t ∈ (- 8, 8), then we have a line in 3-space.
Now suppose we wish to define a line segment by the points
and
. We first construct a vector
Figure 1.14. Then, for t ∈[0,1], the graph of the equation is the line segment defined by range t ∈[0,1], then you get a point on the line that coincides with the segment but which is not on the segment.
from and
to
, as shown in
. Note that if you go outside the
Figure 1.14: We generate points on the line segment by plugging in different values for t in [0,1]. For example, the midpoint of the line segment is given at t = ½. Also note that if t = 0, we get
, and if t = 1, we get
.
25
1.7 D3DX Vectors In this section, we spend some time becoming familiar with the D3DXVECTOR3 class, which is the class we often use to store the coordinates of both points and vectors in code relative to some coordinate system. Its class definition is: typedef struct D3DXVECTOR3 : public D3DVECTOR { public: D3DXVECTOR3() {}; D3DXVECTOR3( CONST FLOAT * ); D3DXVECTOR3( CONST D3DVECTOR& ); D3DXVECTOR3( CONST D3DXFLOAT16 * ); D3DXVECTOR3( FLOAT x, FLOAT y, FLOAT z ); // casting operator FLOAT* (); operator CONST FLOAT* () const; // assignment operators D3DXVECTOR3& operator += D3DXVECTOR3& operator -= D3DXVECTOR3& operator *= D3DXVECTOR3& operator /=
( ( ( (
CONST CONST FLOAT FLOAT
D3DXVECTOR3& ); D3DXVECTOR3& ); ); );
// unary operators D3DXVECTOR3 operator + () const; D3DXVECTOR3 operator - () const; // binary operators D3DXVECTOR3 operator D3DXVECTOR3 operator D3DXVECTOR3 operator D3DXVECTOR3 operator
+ * /
( ( ( (
CONST CONST FLOAT FLOAT
D3DXVECTOR3& ) const; D3DXVECTOR3& ) const; ) const; ) const;
friend D3DXVECTOR3 operator * (FLOAT, CONST struct D3DXVECTOR3& ); BOOL operator == ( CONST D3DXVECTOR3& ) const; BOOL operator != ( CONST D3DXVECTOR3& ) const; } D3DXVECTOR3, *LPD3DXVECTOR3; Note that D3DXVECTOR3 inherits its coordinate data from D3DVECTOR , which is defined as: typedef struct _D3DVECTOR { float x; float y; float z; } D3DVECTOR; In addition to the above class, the D3DX library includes the following useful functions for computing the length of a vector, normalizing a vector, computing the dot product of two vectors, and computing the cross product of two vectors.
FLOAT D3DXVec3Length(
// Returns
CONST D3DXVECTOR3 *pV);
// Input
D3DXVECTOR3* D3DXVec3Normalize(
D3DXVECTOR3 *pout,
// Outputs
CONST D3DXVECTOR3 *pV);
// Input
FLOAT D3DXVec3Dot( CONST D3DXVECTOR3 *pV1,
// Outputs // Input
CONST D3DXVECTOR3 *pV2); // Input D3DXVECTOR3 *D3DXVec3Cross( D3DXVECTOR3 *pout,
// Outputs
CONST D3DXVECTOR3 *pV1,
// Input
CONST D3DXVECTOR3 *pV2); // Input Note Remember to link the d3dx9.lib library file with your application to use any D3DX code; moreover, you will also need to #include . The following short code provides some examples on how to use the D3DXVECTOR3 class and the four functions mentioned above. #include #include using namespace std; // Overload the "