1. Trang chủ
  2. » Công Nghệ Thông Tin

Microsoft XNA Game Studio Creator’s Guide- P16 ppt

30 309 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Microsoft XNA Game Studio Creator’s Guide
Trường học Microsoft
Chuyên ngành Game Development
Thể loại Guide
Định dạng
Số trang 30
Dung lượng 365,46 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Add ProjectedXZto the game class to interpolate the X and Z positions for objects in leading and trailing cells: public Vector3 ProjectedXZVector3 position, Vector3 speed, float changeX

Trang 1

These next instructions belong inside LoadContent() to load the spaceshipmodel:

shipModel = Content.Load<Model>("Models\\alien1");

shipMatrix = new Matrix[shipModel.Bones.Count];

shipModel.CopyAbsoluteBoneTransformsTo(shipMatrix);

UpdateShipPosition()is used in the game class to not only move the ship on

X and Z but also Y to match the height of the terrain below:

void UpdateShipPosition(GameTime gameTime){

const float HOVER_DISTANCE = 0.04f;

// ship's X, Y, Z position without hover distance above the ground shipPosition.Y = shipPosition.Y - HOVER_DISTANCE;

// reverse direction if right boundary exceeded

if (shipPosition.Z < -BOUNDARY && positiveDirection == false){

shipVelocity *= -1.0f;

positiveDirection = true;

}

// reverse direction if left boundary exceeded

else if (shipPosition.Z > BOUNDARY && positiveDirection == true){

shipPosition.X+= shipVelocity.X * time;

shipPosition.Y = CellHeight(shipPosition) + HOVER_DISTANCE;

428

Trang 2

When you’re drawing the spaceship, the ship’s Up vector is calculated using a

weighted average of leading and trailing normal vectors in the ship’s path (see Figure

25-5) This weighted average prevents a jerking motion caused as the ship’sUpvector

changes from one cell to the next If you want to make it look as if you don’t have any

shock absorption, you can just use the normal vector for the current cell only

Whether you are calculating weighted or normal vectors, a method is required to

project or interpolate the object’s position ahead or behind When

directionScalarequals +1, the position in one cell ahead is determined When

directionScalar equals -1, the position one cell behind is determined Add

ProjectedXZ()to the game class to interpolate the X and Z positions for objects

in leading and trailing cells:

public Vector3 ProjectedXZ(Vector3 position, Vector3 speed,

float changeX = directionScalar * terrain.cellWidth * velocity.X;

float changeZ = directionScalar * terrain.cellHeight * velocity.Z;

return new Vector3(position.X + changeX, 0.0f, position.Z + changeZ);

}

CellWeight()determines the remaining distance within the current cell relative

to the total distance projected into the neighboring cell This fraction is then used to

Trang 3

weight the height values and Up vectors in trailing and leading height map cells.CellWeight()belongs in the game class:

float CellWeight(Vector3 currentPosition, Vector3 nextPosition){

Vector3 currRowColumn = RowColumn(currentPosition);

int currRow = (int)currRowColumn.Z;

int currCol = (int)currRowColumn.X;

Vector3 nextRowColumn = RowColumn(nextPosition);

int nextRow = (int)nextRowColumn.Z;

int nextCol = (int)nextRowColumn.X;

// find row and column between current cell and neighbor cell

int rowBorder, colBorder;

colBorder = currCol; // next cell at left of current cell

Vector3 intersect = Vector3.Zero; // margins between current

// and next cell intersect.X = -BOUNDARY + colBorder*terrain.cellWidth;

intersect.Z = -BOUNDARY + rowBorder*terrain.cellHeight;

currentPosition.Y = 0.0f; // not concerned about height

// find distance between current position and cell border

Vector3 difference = intersect - currentPosition;

float lengthToBorder = difference.Length();

// find distance to projected location in neighboring cell

difference = nextPosition - currentPosition;

float lengthToNewCell = difference.Length();

if(lengthToNewCell==0) // prevent divide by zero

return 0.0f;

// weighted distance in current cell relative to the entire

430

Trang 4

// distance to projected position

return lengthToBorder / lengthToNewCell;

}

Since the normal vector is projected in the cell ahead or trailing cell behind, an

ad-justment is required to handle situations where the current and projected cell are

both off the height map Replace the existingHandleOffHeightMap()method

with this revision to remedy this case If you don’t, you will notice the spaceship

dis-appears when it reaches the end of the world when Z is positive:

private void HandleOffHeightMap(ref int row, ref int col){

CellNormal()receives the height map row and column as parameters and

re-turns the corresponding normal vector The normal vector serves as a measure of

up-rightness for the object travelling above this location:

Vector3 CellNormal(int row, int col){

HandleOffHeightMap(ref row, ref col);

return terrain.normal[col + row * terrain.NUM_COLS];

}

Normal()projects the normal vector inside the cell according to the position

rel-ative to the surrounding height map cell vertices Chapter 24 explains theLerp()

calculation behind this projection:

Vector3 Normal(Vector3 position){

// coordinates for top left of cell

Vector3 cellPosition = RowColumn(position);

int row = (int)cellPosition.Z;

int col = (int)cellPosition.X;

// distance from top left of cell

float distanceFromLeft = position.X%terrain.cellWidth;

Trang 5

float distanceFromTop = position.Z%terrain.cellHeight;

// use lerp to interpolate normal at point within cell

Vector3 topNormal = Vector3.Lerp(

CellNormal(row, col), CellNormal(row,col+1), distanceFromLeft); Vector3 bottomNormal = Vector3.Lerp(

CellNormal(row+1,col),CellNormal(row+1,col+1),distanceFromLeft); Vector3 normal = Vector3.Lerp(

topNormal, bottomNormal, distanceFromTop); normal.Normalize(); // convert to unit vector for consistency

return normal;

}

NormalWeight()is needed in the game class to allocate a weighted portion foreach normal vector contained in a fixed range along the object’s path, as shown inFigure 25-5 These weighted normal vectors are later combined to generate the up-right vector for the spaceship If you only use the current normal vector for yourship’sUpdirection, you will notice sudden changes in orientation at each cell and theride will appear to be a rough one:

Vector3 NormalWeight(Vector3 position, Vector3 speed,

float numCells, float directionScalar){

float weight = 0.0f;

float startWeight = 0.0f;

float totalSteps = (float)numCells;

Vector3 nextPosition;

Vector3 cumulativeNormal = Vector3.Zero;

for (int i = 0; i <= numCells; i++)

{ // get position in next cell

nextPosition = ProjectedXZ(position, speed, directionScalar);

if (i == 0){ // current cell startWeight = CellWeight(position, nextPosition);

weight = startWeight/totalSteps;

} else if (i == numCells) // end cell weight = (1.0f - startWeight)/totalSteps;

else // all cells in between weight = 1.0f/totalSteps;

432

Trang 6

ProjectedUp()drives the normal vector calculation for the ship from the game

class This method ensures that your ship is oriented properly above the terrain face:

Vector3 ProjectedUp(Vector3 position, Vector3 speed, int numCells){

Vector3 frontAverage, backAverage, projectedUp;

// total steps must be 0 or more 0 steps means no shock absorption.

if (numCells <= 0)

return Normal(position);

// weighted average of normals ahead and behind enable smoother ride.

else{

frontAverage = NormalWeight(position, speed, numCells, 1.0f);

backAverage = NormalWeight(position, speed, numCells,-1.0f);

ShipWorldMatrix()assembles the cumulative transformation for the

space-ship It performs the same scaling and translation routine that we have implemented

in previous chapters.ShipWorldMatrix()also calculates the ship’s orientation

according to both the ship’s direction and the slope of the terrain underneath The

di-rection matrix used is described in more detail in Chapter 8 These are the steps used

to generate the direction matrix (refer to Figure 26-6):

1. Initialize a direction matrix using a fixed rotation about the Y axis This is

arbitrary but the direction vectors contained within this matrix will be

corrected later

2. Calculate the properUpvector using a weighted average of leading and

trailing normal vectors on the ship’s path, as shown in Figure 25-5

3. Generate theRightvector from the initialForwardand weightedUp

vector

4. Calculate the properForwardvector using the cross product of theUp

andRightvectors

Trang 7

Matrix scale = Matrix.CreateScale(0.3f, 0.3f, 0.3f);

Matrix translation = Matrix.CreateTranslation(shipPosition);

// 1.

// generate direction matrix with fixed rotation about Y axis

Matrix dir = Matrix.CreateRotationY(MathHelper.Pi);

Vector3 velocity = Vector3.Normalize(shipVelocity);

dir.Right = Vector3.Normalize(dir.Right);

// 4.

// Re-calculate FORWARD with known UP and RIGHT vectors

dir.Forward = Vector3.Cross(dir.Up, dir.Right);

F I G U R E 2 5 - 6

Direction matrix

Trang 8

dir.Forward = Vector3.Normalize(dir.Forward);

// apply other transformations along with direction matrix

return scale * rotationY * dir * translation;

}

DrawModel()is needed in the game class to draw the ship It draws the ship at

the position and with the orientation to fit the terrain location and slope:

void DrawModel(Model model){

// declare matrices

Matrix world = ShipWorldMatrix();

foreach (ModelMesh mesh in model.Meshes){

foreach (BasicEffect effect in mesh.Effects)

When you run the program, your hills will appear, and as you move over them the

camera will rise and fall with their elevation The spaceship will travel back and forth

riding the changes in terrain slope As you can see, this impressive effect was created

with very little effort

If you like the textures generated by the noncommercial version of Terragen, you

should consider purchasing a license so you have the ability to create even larger

im-age sizes and you can access more features

Trang 9

C HAPTER 25 REVIEW EXERCISES

To get the most from this chapter, try out these chapter review exercises

1. Implement the step-by-step demonstration discussed in this chapter, if youhave not already done so

2. Reduce theCELL_SPANvalue to 0 inShipWorldMatrix()and run yourgame code Notice the spaceship ride is much rougher because the normalvectors are not weighted

3. Create your own height map Load it into your application To add detail,apply multitexturing to the terrain

4. Modify theheightScalevalue inside TerrainContent.cs to heighten orflatten your terrain

5. If you are feeling ambitious, try adjusting the camera’s view vector tochange with the slope of the terrain just as the spaceship does

436

Trang 10

CHAPTER 26

Animated Models

Trang 11

WE are sure you will agree that animated models are among the most excit-ing features of any game This chapter presents several options for ating and loading pre-animated 3D models in your code XNA does not currentlyship with a library that automatically animates 3D models, so you have to find aloader that you can integrate into your code or you have to write your own animatedmodel loader As an alternative, we provide a model loader that loads and displays

cre-animated Quake II models, which are stored in the md2 model format.

Of course, you can use MilkShape to create and export your animated models to.md2 format However, if you are using a different model loader for other 3D modelformats, you may still be able to create your model in MilkShape and then export it toyour desired format Alternatively, if you developed your 3D model in another 3Dmodel tool, you may be able to import it into MilkShape, animate it, and then export

it to a Quake II model format or other format, as needed.

Whatever method you use to develop your models, make sure you test the loadand display of your 3D models from your XNA code It is worth the time to ensureyour models load and animate properly in your loader before you invest heavily increating and animating them

T HE QUAKE II FORMAT

This chapter does not fully explain how the animated Quake II model source code

works However, a brief overview of the md2 format is presented, and if you need to

study it more, all of the Quake II model loader code is available with this book for

you to view and modify This chapter explains how you can add this MD2 class toplay your animations, change animations, play sequences of animations, or pauseand resume your animations

The MD2 format was developed by id Software, and it was first introduced as part

of id Software’s Quake II id Software has since released the source code for their

Quake II game engine to the public under the GNU General Public License Since

then, the Quake II model format has become popular with game coders because it is

reliable for animations, it is easy to implement, and decent low-cost tools are able to create models

avail-The Quake II format implements animation entirely through keyframe

anima-tions The model’s vertices are positioned at each keyframe During the animation,the vertices are projected according to their relative position on the timeline betweenthe closest keyframes

When creating Quake II models in a modeling tool such as MilkShape, you attach the groups of vertices (known as meshes) to bones These bones are connected by a

series of joints to create the skeleton The bones can be moved and rotated at differentframes in the timeline to create keyframes The attached meshes move with the boneswhen you create the animation The joints keep the bones together to ensure yourmeshes move properly within the skeletal system for the model When you export the

Trang 12

C H A P T E R 2 6

model and keyframes to the md2 format, the bones are thrown out and you are left

with a header file that describes the model’s vertex data, the texture or skin

informa-tion, and the information about the keyframe animations

Unlike other model formats, Quake II models do not use the skeletal hierarchy or

skin weights that are assigned during the model-creation process This absence of

in-formation can lead to unrealistic crinkling of skin around model joints However,

you can avoid this crinkling (or minimize it) with careful planning while designing

your model Up close your Quake II model skins may appear to be a bit wobbly or

watery due to their keyframe animation, but this defect isn’t noticeable from most

distances

Quake II models cannot use more than 4,096 triangles However, this limitation

is reasonable because you can still generate decent-looking models with this polygon

count

A Closer Look at the md2 Data

This section provides a brief overview of how the md2 file is loaded and how it

en-ables your animated models

The Quake II data is stored in binary format in a manner that permits for some

compression of the vertex and frame data To help you unravel this data, the start of

the file contains a header that describes the file type, the texture properties, the vertex

properties, the total number of vertices, the total number of frames, and binary

off-sets in the file (to access details about the vertices and animation frames) Here is the

standard md2 header:

struct md2{ int fileFormatVersion; // file type which must equal 844121161

int version; // file format version which must be 8

int skinWidth; // texture width

int skinHeight; // texture height

int frameSize; // bytes per frame

int numSkins; // total skins used

int numVertices; // total vertices per frame

int numUVs; // total texture UV's

int numTris; // number of triangle coordinates

int numglCommands; // number of glCommands

int numFrames; // number of keyframes

int offsetSkins; // binary offset to skin data

int offsetUV; // offset to texture UV data

int offsetTriangle; // offset to triangle list data

int offsetFrames; // offset to frame data

int offsetglcmds; // offset to OpenGL command data

int offsetEnd; // offset to end of file

};

Trang 13

Each vertex in every frame is indexed The indexes are ordered in a sequence of angle lists When the file is loaded, the indices are used to generate a list of vertex co-ordinates The coordinates are then used to build a series of triangle lists Forefficiency, you could use the glCommands data to rewrite your model-loading andanimation code to render your models using triangle strips or triangle fans

tri-As you would expect, it is possible to store more than one animation with the

Quake II format For example, your model may have a running, jumping, taunting,

saluting, crouching, and idling animation You will want to be able to switch tween these animations on demand To access this information, use the md2 header,which contains the offset to the frame descriptions The frame descriptions can beread in using a binary read at the offset All frame descriptions are located togethersequentially from the starting frame to the very last frame Each frame description in-cludes an animation name and a frame number

be-To determine the starting and ending frames for each individual animation, youmust parse each frame description so you can match the animation names Once youhave a series of matching animation names, you can store the starting and endingframe numbers in this series When you want to play the animation on demand, youcan set the frame number to the starting frame in the animation series When the ani-mation reaches the last frame, you can start the animation over again or you canswitch to another animation

During the animation sequence, the vertices are projected on the timeline betweenthe keyframes used in the animation The normal vectors must also be interpolated inthis manner

Textures with md2 Format

For the actual Quake II game, Quake II models use pcx files for textures However,

the pcx format is not supported in XNA’s content pipeline A way to get around thislimitation is to use an image-editing program such as the freeware image editorGIMP to load your *.pcx skins and save them to *.tga format, which is supported in

the content pipeline You can then use the *.tga files to texture your Quake II els Although it is possible to have more than one texture for a Quake II model, the

mod-Quake II model loader provided with this chapter only handles one texture or skin.

When you build your Quake II models, be sure to use only one skin Thecode used in this chapter can only handle one skin

A NIMATING MODELS IN MILKSHAPE

To show you how to create an animated model using MilkShape, this example onstrates how to create an animated lamp that pivots left and right and also performs

dem-a bowing dem-animdem-ation

Trang 14

Creating the Quake II Model

Before you can create an animation, you first need to create a model You can create

your own model, use the one that is provided with the book, or search online for one

to use

Creating the Meshes

Your first task is to create two separate meshes for the top and bottom portions of a

lamp, similar to the ones shown on the left side of Figure 26-1 For a refresher on how

to use MilkShape to create meshes like these, review Chapter 14, “3D Models.”

To enable smooth animations, be sure to position your model at the origin

Once you have created your meshes, you need to position them together so they

appear as one lamp However, to enable the animation, you must ensure that the

meshes remain as two separate groups If your model uses more than two mesh

groups, you will need to merge them so you end up with a top mesh group and a

bot-tom mesh group Merging can be performed on the Groups tab using the Regroup

button (Merging groups is also explained in Chapter 14.)

Creating the Skeleton

Once you have the top and bottom mesh groups in position, you must add three

joints to create pivot points for the animation The end result is shown in the diagram

on the right in Figure 26-1

Joints can be added in MilkShape from the Model tab While the Joint button is

se-lected, click into the viewport to add a joint where the cursor is placed To enable

Trang 15

proper mesh positioning with the bones (when animating your lamp model), youmust add each of the three joints in sequence from the bottom to the top The firstjoint is placed at the base of the lamp After the first joint is set, whenever a new joint

is added, a bone is automatically generated between the new joint and the joint thatwas previously added

To enable use of the bones as guides for the mesh animations, you must attach themeshes to the bones The bottom mesh will be attached to the bottom bone You can

select the bottom bone by clicking the joint listed at the top on the Joints tab, then lect the bottom mesh When doing this, choose the Select button on the Groups tab to

se-ensure the bottom mesh is the only mesh group highlighted in red When the bottommesh group is highlighted in red and the bottom joint is also highlighted in red, click

the Assign button on the Joints tab to assign the bottom mesh to the bottom bone Figure 26-2 shows the viewport and Joints tab where the bottom mesh has been as-

signed to the lower bone

Next, you must repeat this process to assign the top mesh to the top bone To select

the top bone, click the middle joint, which is joint2, to highlight it in red Then select the top mesh in the viewport on the Groups tab and ensure that is the only one high- lighted in red Once both the top joint and top mesh are selected, click the Assign but- ton on the Joints tab to attach the upper mesh to the upper bone.

To ensure you have the correct mesh attached to the correct bone, you canselect the joint on the Joints tab and click the SelAssigned button to highlightthe mesh that is attached

442

F I G U R E 2 6 - 2

Attaching the bottom mesh to the bottom bone

Ngày đăng: 02/07/2014, 06:20

TỪ KHÓA LIÊN QUAN