Calculating the angle of direction can bedone using several methods.. Calculating Direction Using Speed When Y is constant, the change in X and Z, during each frame, measures speed.. Cal
Trang 1ro-earthRotation += gameTime.ElapsedGameTime.Milliseconds/1000.0f;
earthRotation = earthRotation%(2.0f * MathHelper.Pi);
moonRotation += (float)TargetElapsedTime.Milliseconds/750.0f;
moonRotation = moonRotation %(2.0f * MathHelper.Pi);
Here are the five recommended steps for drawing the revolving Earth object:
1. Declare the matrices
2. Initialize the matrices The identity matrix is initialized as a default matrix
in the event of no transformations (Try leaving it out of the transformation,
Earth and moon example
Trang 2and notice you still get the same result.) A matrix that generates the earth’s
revolution on the Y axis is computed based on a constantly changing angle
(in radians) Every frame, the angle is incremented with a value based on
the time lapse between frames This time-scaled increment to the rotation
angle ensures that the animation appears smoothly while maintaining a
constant rate of change Scaling the increment based on time is necessary
because durations between frames can vary depending on other tasks being
performed by the operating system Finally, a translation is created to movethe earth 0.5 units upward on the Y axis and 8.0 units inward on the Z axis
3. The World matrix is built by multiplying each of the matrices in the
transformation using the I.S.R.O.T sequence
4. The World matrix used to transform the earth is passed to the shader as
part of the World*View*Projection matrix
5. The triangle is rendered by drawing vertices with a triangle strip
AddingDrawEarth()to the game class provides the code needed for ing and drawing theEarth:
transform-private void DrawEarth(){
// 3: build cumulative World matrix using I.S.R.O.T sequence
// identity, scale, rotate, orbit(translate & rotate), translate
world = rotationY * translation;
// 4: set shader parameters
Trang 3Next, theDrawMoon()method implements the same five-step drawing routine totransform and render the same vertices as aMoonobject The moon has its own revo-lution about the Y axis, and it also orbits around the earth In addition, the moon isscaled to one-fifth the size of the earth
The DrawMoon() method performs all of the same transformations as theDrawEarth()method Plus,DrawMoon()implements scaling and an orbit All ofthe matrices declared in theDrawEarth()method are declared inDrawMoon()toperform the same transformations Also, additional matrices are declared and set inthis method to handle the scaling and orbit The scale is set to draw the object atone-fifth the size of the earth by assigning the scale matrix the following value:
Matrix.CreateScale(0.2f, 0.2f, 0.2f);
Remember that the orbit is a two-step process that involves a translation followed
by a rotation When the World matrix is built, the crucial I.S.R.O.T sequence is used
to ensure that the matrices are multiplied in the proper order:
world = scale * rotationY * orbitTranslation * orbitRotationY
* translation;
Since the same vertices are used for drawing theMoonand theEarth, steps 4 and
5 ofDrawMoon()are identical to those inDrawEarth()
private void DrawMoon(){
// 3: build cumulative World matrix using I.S.R.O.T sequence
// identity, scale, rotate, orbit(translate & rotate), translate
world = scale * rotationY * orbitTranslation
* orbitRotationY * translation;
Trang 4Both theDrawEarth()andDrawMoon()methods are called from theDraw()
method in the game class:
DrawEarth();
DrawMoon();
When you compile and run this code, it will show the earth as a revolving triangle
being orbited by a revolving moon (refer to Figure 7-2)
Spend the time you need to ensure that you understand transformations It is not an
overly complex topic, but it can be challenging for beginner graphics programmers
who do not give transformations the learning time the topic deserves You will enjoy
the rest of the book more when you have mastered this introduction to animation
Be fearless when experimenting with your transformations When you test and
run your projects, you will probably know right away if your transformations are
working properly Of course, use the documentation presented in this section as a
guide to understanding the topic The real learning will happen when you try to
cre-ate your own transformations
To get the most from this chapter, try out these chapter review exercises
1. Implement the step-by-step example presented in this chapter, if you have
not already done so
2. Using primitives, create a stationary airplane with a rotating propeller that
is made from triangles, as in the following illustration When initializing
the vertices that store the propeller, be sure to center the X, Y, and Z
coordinates around the origin Failure to center the X, Y, and Z coordinates
of your surface about the origin will offset your rotations and will lead to
strange results when unbalanced objects are transformed (see Figure 7-3)
Trang 53. When you finish Exercise 2, transform your propeller so it serves as a rotorfor a helicopter Using the same set of vertices, write another procedure totransform and render the same rectangle used for the main rotor as a backrotor, as shown here in Figure 7-4.
Trang 6CHAPTER 8
Character Movement
Trang 7AFTER reading and applying the material covered in Chapter 7,you should be comfortable performing simple animationswith translations and rotations For most gamers, it is not enough just to make a birdflap its wings or make the propeller of an airplane spin; anybody with half an ounce
of curiosity wants to see these objects actually fly This chapter introduces a simpleanimation method that allows moving objects to travel independently within your3D world
Additional methods for enabling the movement of objects are covered inChapter 21
Regardless of the method used to move objects and characters, basic movement isgenerated by updating the X, Y, and Z position coordinates, as well as the rotationangles of the moving object rendered at every frame
When you animate vehicles that fly, drive, sail, or glide, you most likely expect them
to point in the direction they are traveling Calculating the angle of direction can bedone using several methods Without this calculation, your vehicles could look as ifthey are flying backward or even sideways Trigonometry offers a simple intuitiveapproach to calculate the angle of direction—this method will be used often through-out this book However, computing direction can also be done with vectors Usingvectors to calculate direction is actually a more powerful method for implementingrotations of direction because they offer a simpler means to implement complextransformations for directions in all planes
Calculating Direction Using Trigonometry
The trigonometry applied in this chapter is actually quite simple and only involvesusing the arctangent function The arctangent function enables calculations of direc-tion about the Y axis when the X and Z coordinates of the object are known.When the Right Hand Rule is used, all positive rotations are counterclockwise Tocalculate an object’s angle about the Y axis, draw a line from the object’s position tothe preceding axis in the rotation to create a right-angle triangle The tangent of theangle between the hypotenuse and the axis can be calculated with the following equa-tion:
tan φ side length / adjacent side length (where φ is the angle)
Trang 8This equation can be rearranged to isolate the angle:
φ = tan–1 (opposite / adjacent)
φ = atan (opposite / adjacent)
Figure 8-1 shows the angle about the Y axis in relation to the hypotenuse,
oppo-site, and adjacent sides of the right-angle triangle
Calculating Direction Using Speed
When Y is constant, the change in X and Z, during each frame, measures speed On
a three-dimensional graph, the X and Z speed combination will always fall in one
of four quadrants, depending on whether each of the X and Z speeds is positive or
negative
Calculating Direction Using the Math.Atan()
Function
To calculate the angle of direction about the Y axis, create an imaginary right-angle
triangle by drawing a line from the X, Z coordinate to the preceding X or Z axis This
line must be perpendicular to the X or Z axis You can use XNA’sMath.Atan()
function to compute the angle of rotation about the Y axis using the corresponding X
and Z values as opposite and adjacent parameters:
double radians = Math.Atan( (double)opposite/(double)adjacent );
Trang 9TheMath.Atan()function then returns the angle of rotation about Y for the mediate quadrant An offset that equals the total rotation for the preceding quad-rants is added to this angle to give the total rotation in radians Figure 8-2 illustratesthe relationship between the X and Z speeds for each quadrant and their offsets.When theMath.Atan()function is used, each quadrant uses a slightly differentequation to generate the rotation about the Y axis These individual quadrant equa-tions are summarized in Table 8-1.
im-Understanding this basic trigonometry can help you develop algorithms to ate your own direction angles
gener-106
Calculating angle of direction about the Y axis using speed quadrants
Quadrant Offset Equation
Trang 10Calculating Direction Using the Math.Atan2()
Function
Thankfully, there is an easier way to employ trigonometry to calculate the angle of
direction about the Y axis TheMath.Atan2()function eliminates the need to
fac-tor quadrant differences into the calculations To compute the angle of rotation
about the Y axis with theMath.Atan2()function, the calculation becomes this:
double radians = Math.Atan2((double) X / (double) Z)
This equation can be used to calculate the angle of direction about the Y axis for
all quadrants
Both theMath.Atan()andMath.Atan2()functions will be demonstrated in
the example presented in this chapter
Calculating Direction Using Vectors
Calculating direction using vectors is the more powerful method The math behind
implementing vectors of direction is explained in more detail later, in Chapters 15,
16, and 17, so you may choose to read these chapters first for a better understanding
of how the vectors work The vector logic for calculating direction is being presented
ahead of these chapters to ensure you have a better way to move your vehicles,
ves-sels, and aircraft through your 3D world
The vectors that describe the orientation of a moving object can be summarized
using theLook,Up, andRightvectors These vectors describe the moving object’s
direction and uprightness (see Figure 8-3)
TheLookvector, also known as theForwardvector, is calculated from the
differ-ence in the view position and the position of the object When you are animating
ob-jects, theLookvector could also be the same as the object’s speed vector TheUp
vector describes the upright direction For most objects that are animated in this
book, the starting upright direction is 0, 1, 0 When we stand on our own two feet, we
have anUpvector of 0, 1, 0 TheRightvector describes the perpendicular from the
surface created by theUpand Lookvectors TheRightvector can be used for a
strafe in addition to assisting with the computation of angles of direction
If theUpvector is known, theRightvector can be calculated using the cross
prod-uct of theLookandUpvectors TheRightvector equals the cross product of theUp
andLookvectors
Trang 11When these vectors are normalized, or scaled so their lengths range between -1and 1, they can be used in a matrix that calculates the direction The cells of the ma-trix are defined with the data from the three direction vectors:
these vectors with the Matrix struct’s Right, Up, and Forward properties:
Vector3 right = direction.Right;
Vector3 up = direction.Up;
Vector3 look = direction.Forward;
An example showing how to implement this structure is presented later in thechapter
Scaling Animations with Time Lapse Between Frames
When animating objects, it is essential to ensure that your animations run at the samespeed regardless of the processing power of the system that runs them If you are a
Direction vectors
Trang 12starving student, you might only be able to afford a slow PC—maybe with an older
graphics card—but the computers in the labs at your college or university might be
faster, or vice versa If you develop your games on a slow PC, and you don’t regulate
the timing of your animations, they will look as if they are playing in fast forward
when you run them on a faster PC The reverse is true if you develop your games on a
super-charged PC and then run them on a slower machine Also, when you port your
games over to the Xbox 360, you are almost certain to experience a difference in
pro-cessing power compared to your development PC To compound this issue, every
frame of your game will exert different demands on the processor, and you might be
running other programs in the background that are stealing valuable processor
cy-cles With all of these varying system and performance factors to consider, a
mecha-nism to control the speed of your animations is a must-have item
The trick to controlling animation speed is simple The equation used to control
the translation speed looks like this:
Vector3 Position += Increment.XYZ * TimeBetweenFrames / ConstantScale;
Controlling rotation speed is similar:
float radians += Increment * TimeBetweenFrames / ConstantScale;
These equations offer a self-adjusting mechanism to account for varying frame
rates For example, a faster machine will produce more frames, but the animation
won’t run faster, because the time scale will reduce the increment for each frame In
the end, you will have more frames and a smoother animation, but the animation
speed will be the same as an animation that runs on a slower machine If you do not
factor in the time difference between frames, your animations will run at
uncontrol-lable speeds
Character Movement Example
In this example, you will animate a single-prop aircraft so that it flies within the
boundaries of your virtual world Of course, you will also ensure that the plane is
pointing in the direction it’s supposed to fly; first with methods that use trigonometry
and then with methods that use direction vectors This example demonstrates how to
use animations that involve translations and rotations, how to animate an object at a
constant speed, and how to calculate the angle of direction using a constant speed
To keep this example simple, the airplane is built with nothing more than a
trian-gle for the body and a spinning rectantrian-gle for the propeller (see Figure 8-4)
Trang 13If you want, you can easily swap these primitive objects with 3D models; the quence of instructions to create the transformation for the animation would remainidentical
se-This example begins with either the files in the MGHWinBaseCode project or theMGH360BaseCode project from the BaseCode folder on this book’s website
A Stationary Airplane with a Spinning PropellerThis first part of the demonstration explains how to create an airplane using a sta-tionary triangle and a rotating rectangle that is perpendicular to the front tip of thetriangle Two separate objects for storing vertices are needed: the body of the air-plane and the propeller Their declarations are required in the module-level area ofthe game class:
VertexPositionColor[] airplaneVertices = new VertexPositionColor[3];
VertexPositionColor[] propellerVertices = new VertexPositionColor[4];
Code to initialize each vertex—in both the airplane and the propeller—sets the sition and color values for each coordinate Note that the vertices for each object arecentered around the origin As explained previously, any space from the origin to thecenter of an object is actually a translation that will literally send your object into an
Airplane animation
Trang 14orbit when you rotate it If you have already felt the mental pain from trying to debug
this problem before realizing your vertices are not centered—welcome to the club!
The methods InitializeAirplaneBody() and InitializePropeller()
are added to the game class to initialize each array of vertices:
private void InitializeAirplaneBody(){
Vector3 position;
Color color = Color.Orange;
position = new Vector3(0.0f,-0.25f, 0.5f); // lower front
airplaneVertices[0] = new VertexPositionColor(position, color);
position = new Vector3(0.0f, 0.25f,-0.5f); // top back
airplaneVertices[1] = new VertexPositionColor(position, color);
position = new Vector3(0.0f,-0.25f,-0.5f); // lower back
airplaneVertices[2] = new VertexPositionColor(position, color);
}
private void InitializePropeller(){
Vector3 position;
Color color = Color.LightBlue;
position = new Vector3(-0.5f, 0.05f, 0.0f);// top left
propellerVertices[0] = new VertexPositionColor(position, color);
position = new Vector3(-0.5f,-0.05f, 0.0f);// lower left
propellerVertices[1] = new VertexPositionColor(position, color);
position = new Vector3(0.5f, 0.05f, 0.0f);// top right
propellerVertices[2] = new VertexPositionColor(position, color);
position = new Vector3(0.5f, -0.05f, 0.0f);// lower right
propellerVertices[3] = new VertexPositionColor(position, color);
}
To initialize the propeller and the airplane body, when the program begins, call
InitializeAirplaneBody() and InitializePropeller() from
Ini-tialize():
InitializeAirplaneBody();
InitializePropeller();
In the beginning of this demonstration, the airplane is drawn as a stationary
ob-ject A translation matrix generated by the instruction:
translation = Matrix.CreateTranslation(0.0f, 0.75f, -8.0f);
Trang 15world = rotationY * translation;
DrawAirplaneBody()declares and initializes the transformation matrices inthe first two steps Then, the cumulative World matrix is built in the third step In thefourth step, the cumulative transformation stored in the World matrix is sent to theshader Finally, in the fifth step, the triangle is drawn from the transformed vertices.DrawAirplaneBody()is added to the game class to transform and render the ver-tices for the triangle
private void DrawAirplaneBody(){
// 3: build cumulative world matrix using I.S.R.O.T sequence
// identity, scale, rotate, orbit(translate & rotate), translate
world = rotationY * translation;
// 4: set shader parameters
positionColorEffectWVP.SetValue(world * cam.viewMatrix
* cam.projectionMatrix);
// 5: draw object - primitive type, vertices, total primitives
PositionColorShader(PrimitiveType.TriangleStrip,airplaneVertices,1); }
Instructions for rendering the propeller are similar to steps taken to position anddraw the airplane The main difference inDrawPropeller()is the inclusion of acontinuous rotation about the Z axis Adding a variable to the game class to store ro-