Microsoft XNA Game Studio Creator’s Guide- P7 pps

30 293 0
Microsoft XNA Game Studio Creator’s Guide- P7 pps

Đ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

MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 158 Once the indices have been defined, the SetData() method stores the index ref- erences in the index buffer. There are several overrides for this method, but for our needs, all you have to do is pass in the array of indices: SetData<T>(T[] data); Managing Vertex Data with Index Buffers and Vertex Buffers By themselves, the VertexPositionColor, VertexPositionColorTexture, VertexPositionTexture, and VertexPositionNormalTexture objects that you have used will not permit live updates to the position, color, texture, and normal data. DynamicVertexBuffer objects in combination with index buffers, on the other hand, will permit updates to large amounts of vertex data. You are going to want a structure like this when creating an effect such as water. When initialized, the constructor for the vertex buffer takes parameters for the current graphics device, vertex type, element count, and buffer usage for memory al- location: VertexBuffer( GraphicsDevice graphicsDevice, Type vertexType, int elementCount, BufferUsage usage); As explained above, BufferUsage options are None as the default, WriteOnly for efficient writes to memory and for efficient drawing, and Pointsforpoint sprites. After the vertex data is loaded into an array, the vertex data is moved into the ver- tex buffer with the VertexBuffer object’s SetData() method. There are several variations of this method. The method used here only passes the array of vertices: SetData(VertexBuffer[] vertexBuffer) Rendering Vertex Buffers with an Index Buffer Reference The draw method you use for dynamic vertex buffers—using index buffers—differs in three ways from the draw methods you have used until now: 1. The SetSource() method is used to set the vertex buffer that stores the grid, the starting element, and the size of the vertex type in bytes: graphics.GraphicsDevice.Vertices[0].SetSource( VertexBuffer vertexBuffer, int startingElement, int sizeOfVertex ); 159 2. The GraphicsDevice’s Indices object is set with the corresponding IndexBuffer object you defined during the program setup: graphics.GraphicsDevice.Indices = indexBuffer; 3. The DrawIndexedPrimitives() method is used to reference a series of vertex subsets that are rendered in succession to draw the entire polygon or surface. DrawIndexedPrimitives() is called for each vertex subset. graphics.GraphicsDevice.DrawIndexedPrimitives( PrimitiveType primitiveType, int startingPointInVertexBuffer, int minimumVerticesInBuffer, int totalVerticesInBuffer, int indexBufferStartingPoint, int indexBufferEndPoint); Grid Using Index Buffer Example This code will implement an index buffer and dynamic vertex buffer to draw a rect- angle from a set of vertices that is three vertices wide and five vertices long (see Figure 11-3). Drawing a rectangle with a set of vertices that uses index buffers might seem like a lackluster chore, but don’t be fooled. Index buffers have grit. This little exam- ple serves as the foundation for creating water waves in Chapter 12, creating terrain with height detection in Chapter 25, and enabling better lighting across primitive surfaces in Chapter 22. This example begins with either the MGHWinBaseCode or MGH360BaseCode project in the BaseCode folder on this book’s website. CHAPTER 11 Index Buffers FIGURE 11-3 Grid rendered from an index buffer MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 160 To make this vertex reference system work, an index buffer to reference a grid of vertices is required. Also, a vertex buffer object is needed to store the vertices. A ver- tex declaration type is used to set up the buffer when it is being initialized. Add these object declarations to the top of your game class: private IndexBuffer indexBuffer; // reference vertices private VertexBuffer vertexBuffer; // vertex storage The rows and columns used to draw the rectangle will be referenced with identifi- ers to help explain how the vertices are arranged. Add these identifiers to the top of the game class. const int NUM_COLS = 3; const int NUM_ROWS = 5; Indices for referencing the vertex buffer are initialized when the program begins. The index buffer array is sized to store the total number of vertices contained in one subset of the vertex buffer. The code that you need to set up the index reference is contained in the InitializeIndices() method. Add this method to set up your index reference: private void InitializeIndices(){ short[] indices; // indices for 1 subset indices = new short[2 * NUM_COLS]; // sized for 1 subset indexBuffer = new IndexBuffer( graphics.GraphicsDevice,// graphics device typeof(short), // data type is short indices.Length, // array size in bytes BufferUsage.WriteOnly); // memory allocation // store indices for one subset of vertices // see Figure 11-2 for the first subset of indices int counter = 0; for (int col = 0; col < NUM_COLS; col++){ indices[counter++] = (short)col; indices[counter++] = (short)(col + NUM_COLS); } indexBuffer.SetData(indices); // store in index buffer } To initialize the short array and index buffer when the program begins, add the call statement to the Initialize() method: InitializeIndices(); 161 CHAPTER 11 Index Buffers A VertexBuffer object is initialized to store the vertices used to build the primi- tive surface. The VertexBuffer object in this example is static and only stores the vertices that are used to draw the grid or surface. Still, the vertex buffer works in con- junction with the index buffer as a reference to reduce the total number of vertices that build the grid or surface. This type of static vertex buffer is especially useful for drawing lit objects or even terrain where many vertices are needed for detail. When setting up a vertex buffer, the vertex data is generated and is stored in a temporary ar- ray. Once all of the vertex values have been assembled, the vertex data is then stored in the vertex buffer using the SetData() method. To set up your vertices in this effi- cient buffer, add InitializeVertexBuffer() to your game class: private void InitializeVertexBuffer(){ vertexBuffer = new VertexBuffer( graphics.GraphicsDevice, // graphics device typeof(VertexPositionColorTexture), // vertex type NUM_COLS * NUM_ROWS, // element count BufferUsage.WriteOnly); // memory use // store vertices temporarily while initializing them VertexPositionColorTexture[] vertex = new VertexPositionColorTexture[NUM_ROWS*NUM_COLS]; // set grid width and height float colWidth = (float)2 * BOUNDARY/(NUM_COLS - 1); float rowHeight = (float)2 * BOUNDARY/(NUM_ROWS - 1); // set position, color, and texture coordinates for (int row=0; row < NUM_ROWS; row++){ for (int col=0; col < NUM_COLS; col++){ // set X, Y, Z float X = -BOUNDARY + col * colWidth; float Y = 0.0f; float Z = -BOUNDARY + row * rowHeight; vertex[col + row * NUM_COLS].Position = new Vector3(X, Y, Z); // set color vertex[col + row * NUM_COLS].Color = Color.White; // set UV coordinates to map texture 1:1 float U = (float)col/(float)(NUM_COLS - 1); float V = (float)row/(float)(NUM_ROWS - 1); vertex[col + row * NUM_COLS].TextureCoordinate = new Vector2(U, V); } } // commit data to vertex buffer vertexBuffer.SetData(vertex); } The vertices must be set when the program begins, so add a call to initialize the grid vertices in the Initialize() method: InitializeVertexBuffer(); When a dynamic vertex buffer is being rendered, the SetSource() method reads data from the vertex buffer that was initialized earlier. The vertex format is passed into the SetSource() method, so the GraphicsDevice knows how to extract the data, and the GraphicsDevice’s Indices property is assigned the index buffer. Finally, DrawIndexedPrimitives() is executed once for each subset of strips in the grid. Add DrawIndexedGrid() to the games class: private void DrawIndexedGrid(){ // 1: declare matrices Matrix world, translation; // 2: initialize matrices translation = Matrix.CreateTranslation(0.0f, -0.5f, 0.0f); // 3: build cumulative world matrix using I.S.R.O.T. sequence world = translation; // 4: set shader parameters textureEffectWVP.SetValue(world*cam.viewMatrix*cam.projectionMatrix); textureEffectImage.SetValue(grassTexture); // 5: draw object - select vertex type, vertex source, and indices graphics.GraphicsDevice.VertexDeclaration = positionColorTexture; graphics.GraphicsDevice.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionColorTexture.SizeInBytes); graphics.GraphicsDevice.Indices = indexBuffer; // start using Texture.fx textureEffect.Begin(); textureEffect.Techniques[0].Passes[0].Begin(); MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 162 163 // draw grid one row at a time for(intZ=0;Z<NUM_ROWS - 1; Z++){ graphics.GraphicsDevice.DrawIndexedPrimitives( PrimitiveType.LineStrip, // primitive Z * NUM_COLS, // start point in buffer for drawing 0, // minimum vertices in vertex buffer NUM_COLS * NUM_ROWS, // total vertices in buffer 0, // start point in index buffer 2 * (NUM_COLS - 1)); // end point in index buffer } // stop using Texture.fx textureEffect.Techniques[0].Passes[0].End(); textureEffect.End(); } To draw the grid, call DrawIndexedGrid() from the Draw() method: DrawIndexedGrid(); Also, to see the grid when it renders, you will need to comment out the instruction to DrawGround(). When you run the program, the grid appears as shown earlier in Figure 11-3. However, if the grid is drawn with triangle strips, the output will fill in the area be- tween the vertices and display a rectangle. This will happen if you change LineStrip to TriangleStrip in DrawIndexedGrid(). Bystanders might not be impressed that you just created a rectangular surface, but don’t let that bother you. Let’s put this demo on the backburner for now. We’ll return to it in later chapters to let it rip. C HAPTER 11 REVIEW EXERCISES To get the most from this chapter, try out these chapter review exercises. 1. Try the step-by-step example in this chapter, but this time change the number of rows to 125 and the number of columns to 55. View the project using line strips and triangle strips. 2. Compared to methods that are used in previous chapters for storing vertices without an index reference, how many vertices are saved when using an index buffer to draw a grid that is 60 rows high and 35 rows wide? CHAPTER 11 Index Buffers 3. The example presented in this chapter shows how to use a static VertexBuffer object with index buffers. What is the advantage of doing this? What type of vertex buffer permits updates to vertices at run time? 4. List three ways that the DrawIndexedPrimitives() method is different from the DrawUserPrimitives() method. MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 164 CHAPTER CHAPTER 12 Combining Combining Images for Images for Better Visual Better Visual Effects Effects 166 THIS chapter demonstrates various ways of combining images to gen- erate compelling visual effects; more specifically, sprites and multitexturing will be discussed. By the end of the chapter, you will be able to use im- age files that store more than one image frame to create cool heads-up display (HUD) animations in your 2D or 3D games. You will also be able to blend two textures to- gether to generate intricate detail for effects such as terrain or a water simulation. Al- though games are not defined solely by their aesthetics, no one has ever complained that a game’s graphics looked too good. Your players will appreciate any effort you put into maximizing your visual effects. S PRITES As discussed in Chapter 4, a sprite is an animated 2D image. You can animate sprites by moving them in the window. Also, if your sprite has more than one frame, you can swap frames to animate them. Image Frame Swapping for 2D Animations Image frame swapping creates an animation similar to old-style page-flipping anima- tions used to create simple cartoons. The sprite is animated at run time by adjusting the texture’s UV coordinates at fixed time intervals. Sprites store multiple image frames because adjusting UV coordinates at run time—to switch image frames—is faster than switching to a different image file. For 3D games, a 2D sprite offers a very simple way to customize and animate the heads-up display, or a game dashboard. This type of sprite could be used to create an animated radar scope on the console of a flight simulation game. SpriteBatch For the 2D effect, a sprite object is created with the SpriteBatch class: SpriteBatch spriteBatch = new SpriteBatch(GraphicsDevice); A SpriteBatch object is actually already included in the XNA template project code that is generated using the New Project dialog box. For our purposes this is the only one you will need. Primitive objects are not needed to display the image when using SpriteBatch methods. As a result, setting up the sprite is easier than setting up textured primitive surfaces; the SpriteBatch object draws the image on its own. For the 2D object, all drawing is done between the SpriteBatch object’s Begin() and End() methods. 167 The syntax for the Draw() method is designed for drawing on a 2D window. The first parameter references the Texture2D object that stores the image file; the sec- ond parameter references the position, height, and width of a rectangle in the 2D window; and the third parameter references the starting pixel’s X and Y position in the image and the height and width—in pixels—to be drawn. The fourth parameter sets the color of the sprite in case you want to shade it differently from the colors al- ready in the image. Be aware that there are several other overrides for SpriteBatch.Draw(); how- ever, this is the one that we’ll be using for our examples: SpriteBatch.Draw( // Texture2D object Texture2D texture, // window new Rectangle( int topLeftXWindowCoord, int tpLeftYWindowCoord, int displayWidthInPixels, int displayHeightInPixels), // image source new Rectangle( int startingXPixel, int startingYPixel, int pixelWidthDrawn, int pixelHeightDrawn), // color Color Color.ColorType); The rendering for a SpriteBatch object is still triggered from the Draw() method. Restoring 3D Drawing Settings After Drawing with a SpriteBatch If your 3D game uses 2D sprites, you need to be aware of how this will impact your drawing routines. The 2D SpriteBatch automatically resets the GraphicsDevice’s render states to draw 2D graphics in the window. While this is helpful, if the settings are not restored to enable 3D rendering, you may not see your 3D graphics—and if you do, they may not display properly. Ideally, when rendering your SpriteBatch objects, you should draw them last in the Draw() method so that they layer on top of the 3D graphics. CHAPTER 12 Combining Images for Better Visual Effects [...]... in the grid void UpdateMovingSurface(GameTime gameTime){ const float VISIBLE_SECTION = 1.0f/3.0f; // show only 1/3 of image 183 Combining Images for Better Visual Effects C H A P T E R 184 MICROSOFT XNA GAME const float TIME_SCALE STUDIO = 20000.0f; CREATOR’S GUIDE // adjust V by time scale verticalAdjustment // time scale V increment -= (float)gameTime.ElapsedGameTime.Milliseconds/TIME_SCALE; // if... Images for Better Visual Effects C H A P T E R 174 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE Animated Texture Example The previous example is useful for implementing 2D sprites in the game window This example shows how to create a similar effect for textures used inside your 3D world When the example is complete, a flashing “danger” sign will appear in your game Maybe you don’t need a flashing danger sign,... Combining Images for Better Visual Effects C H A P T E R 176 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE The timer code used for this example follows the same algorithm used in the previous example This time, it will set the interval used to display each section of the image Add Timer() to enable frame swapping every 500 milliseconds: bool Timer(GameTime gameTime){ bool resetInterval = false; // add time lapse... is used to load and reference the image To try this example, first add this declaration to the top of the game class: private Texture2D spriteTexture; 169 Combining Images for Better Visual Effects C H A P T E R 170 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE FIGURE 12-1 An animated sprite in the game window A timer is used to trigger the frame change for the sprite, which creates the blinking light animation...168 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE Your graphics device states should be reset to turn off transparency and to re-enable 3D graphics after drawing with the SpriteBatch You must also reset the culling option back to the default used by your game Culling designates the face of an object that is not drawn, so it should... textureEffectImage.SetValue(signTexture); // 5: draw object - primitive type, vertices, #primitives TextureShader(PrimitiveType.TriangleStrip, vertices, 2); } 177 Combining Images for Better Visual Effects C H A P T E R 178 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE Inside the Draw() method, just before the End() method is called for the texture shader, the animated texture needs to be drawn When transparency is involved, the transparent... for the water surface The second image is a picture of similar stones that uses a lighter shade for easier blending In every 179 Combining Images for Better Visual Effects C H A P T E R 180 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE frame, the second image’s texture coordinates are adjusted so that it appears to slide over the first texture The image on the right is actually created from three identical... method You can download the image files from this book’s website They can be found in the Images folder Place this code in 181 Combining Images for Better Visual Effects C H A P T E R 182 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE the LoadContent() method so that the images will be loaded when the program begins: waterTexture[SURFACE0] = Content.Load("Images\\water0"); waterTexture[SURFACE1]... return bounding margins int top, left, height, width; left = (int)(windowWidth * MARGIN); top = (int)(windowHeight * MARGIN); 171 Combining Images for Better Visual Effects C H A P T E R 172 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE width height = (int)((1.0f - UNSAFEAREA) * windowWidth - texture.Width); = (int)((1.0f - UNSAFEAREA) * windowHeight - texture.Height/numFrames); return new Rectangle(left,... Matrix.CreateTranslation(0.0f, -0.5f, 0.0f); // 3: build cumulative world matrix using I.S.R.O.T sequence world = translation; 185 Combining Images for Better Visual Effects C H A P T E R 186 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE // 4: set shader variables textureEffectWVP.SetValue(world*cam.viewMatrix*cam.projectionMatrix); textureEffectImage.SetValue(waterTexture[layer]); // 5: draw object // begin . to be synchronized with real time: MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 170 FIGURE 12-1 An animated sprite in the game window 171 bool Timer(GameTime gameTime){ bool resetInterval = false; //. book’s website. CHAPTER 11 Index Buffers FIGURE 11-3 Grid rendered from an index buffer MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 160 To make this vertex reference system work, an index buffer to reference. using Texture.fx textureEffect.Begin(); textureEffect.Techniques[0].Passes[0].Begin(); MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE 162 163 // draw grid one row at a time for(intZ=0;Z<NUM_ROWS - 1;

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

Tài liệu cùng người dùng

Tài liệu liên quan