Let the 3D Rendering Start (XNA Game Studio 4.0 Programming) Part 2

DrawPrimitives

Unlike the user versions of the draw primitives methods that use arrays to store the vertex data, DrawPrimitive uses a VertexBuffer to store the vertices for your primitives.

A VertexBuffer stores the vertices in the graphics cards hardware memory where they can be quickly accessed. Unlike when using arrays, a VertexBuffer does not require the vertices to be sent from the main system memory to the graphics card each time you want to draw. Sending large amounts of data from the main system memory to the graphics card is not a fast operation and can slow down your rendering speed. So for larger geometry, use a VertexBuffer to store the vertex data and to call the DrawPrimitives method.

First, create two member variables in your Game class: one for the VertexBuffer and another for the BasicEffect.Add the following lines of code to create the member variables:

tmpD-89_thumb[2]

Next, create the VertexBuffer and set the data that is stored inside it.Add the following lines of code to your Game class LoadContent method:


tmpD-90_thumb[2]

 

 

 

tmpD-91_thumb[2]

 

As with the previous example, you first create an instance of BasicEffect and set some of the properties for the transforms and enable vertex coloring.

Again, declare an array of VertexPositionColor and define three vertices. Use this array to set the data to store in the VertexBuffer.

Next, create the instance of the VertexBuffer.The VertexBuffer takes the GraphicsDevice to store the data as the first parameter. Use the GraphicsDevice property of the Game class to use the default GraphicsDevice that is created when your game starts.The second parameter takes the Type of the vertex that is to be stored in the VertexBuffer. Because you want to store vertices of type VertexPositionColor, specify the type using the typeof operator.The third parameter is the number of vertices the VertexBuffer is going to hold. In this case, there are only three vertices.The fourth and final parameter is the BufferUsage. In cases where you know you will never need to read the contents of the VertexBuffer, you can specify BufferUsage.WriteOnly, which causes the VertexBuffer to throw an exception if you ever try to read back any data. Using WriteOnly enables the graphics hardware to chose specific memory locations in the hardware that allow for more efficient drawing.

After the VertexBuffer is created, the SetData method is called to send the vertex data to the graphics hardware. SetData is a generic method that takes the type of vertex data as the generic T parameter.The array of vertices is then passed as the lone parameter. The size of the VertexBuffer must be large enough to store the amount of vertices stored in the array that is passed in. Overloaded versions of SetData are available that enable you to specify an offset, start index, number of vertices to set, and the size of each vertex.These overloads are useful when the source vertex array is slit into multiple vertex buffers.

The final steps you need to draw are to tell the GraphicsDevice the VertexBuffer you plan to use next and to call the DrawPrimitives method. Add the following lines of code to your Game class Draw method:

tmpD-92_thumb[2]

The GraphicsDevice is told which VertexBuffer to use by calling the SetVertexBuffer method and passing in the one you created.This is the VertexBuffer that is used when any DrawPrimitives or DrawIndexPrimitives methods are called until another VertexBuffer is set on the GraphicsDevice. Overloads of SetVertexBuffer are available that enable an offset into the VertexBuffer to be specified.

Next, the EffectPass.Apply method is called like in the previous example.

Finally, call the DrawPrimitives method.The first parameter is the PrimitiveType. The second parameter is the start vertex. This is the vertex in the buffer to start drawing from.This value is combined with any offset value set when SetVertexBuffer is called. The final parameter is the number of primitives to draw, which you set to 1 because you need to draw only the single triangle.

If you run the previous example code, you see output similar to Figure 4.25. Notice how this example and the first example that used DrawUserPrimitives produced the same results but use different functions to draw the primitives.

Using DrawPrimitives to draw a triangle DrawIndexedPrimitives

Figure 4.25 Using DrawPrimitives to draw a triangle DrawIndexedPrimitives

The final draw primitives called DrawIndexedPrimitives uses both a VertexBuffer and an IndexBuffer. Like a VertexBuffer, the IndexBuffer stores data using the graphics hardware’s memory so it can be quickly accessed by the GPU when drawing.The IndexBuffer stores index values like the ones you used previously when using the DrawUserIndexPrimitives method.

To draw indexed primitives using an index buffer, add a member variable to your Game class to hold the instances of the IndexBuffer, VertexBuffer, and BasicEffect.

tmpD-94

In the previous code, you create an array of shorts to store the index values. Because you use a triangle strip, you need only four index values.The IndexBuffer is then cre-ated.The first parameter is the GraphicsDevice where the IndexBuffer is stored.The second parameter is the size each element in the index buffer is. Remember that index values can be 16-bit short values or 32-bit int values.You select IndexElementSize. SixteenBits to specify that 16-bit index values.The fourth parameter is the number of index values the IndexBuffer holds.You specify 4 the size of your index data array. The last parameter is BufferUsage, which is similar to the same parameter on the VertexBuffer.You specify None, which will enables read back if necessary later.

Finally, tell the GraphicsDevice which IndexBuffer to use when the DrawIndexPrimitives method is called.Add the following lines of code to your Game class Draw method:

tmpD-95_thumb[2]

As with the previous examples, you set the VertexBuffer to use and call Apply on the EffectPass you want to use.You also specify the Indices parameter of the GraphicsDevice setting its value to your IndexBuffer.The DrawIndexedPrimitives method is then called to draw a quad on the screen. Like all of the other draw methods, the first parameter is the PrimitveType, which, in this case, is a TriangleStrip.The second parameter is the base vertex, which is an offset that is added to each of the values in the index buffer.The third parameter is the minimum vertex index of all of the vertices used.The fourth parameter is the number of vertices that are going to be used when drawing the triangles. The fifth parameter is the starting index to use in the index buffer. The last parameter like the other draw methods is the number of primitives to draw.

If you run the example code, you should see a colored quad similar to the one in Figure 4.26.

 Using DrawIndexedPrimitives to draw a quad

Figure 4.26 Using DrawIndexedPrimitives to draw a quad

Summary

It is time to take a deep breath.We covered a lot of information about 3D graphics in this topic including what 3D graphics is in regards to interactive games and applications, some of the basic mathematics needed to work with 3D graphics, an overview of the graphics pipeline, and finally how to draw some geometry on the screen using the four main drawing methods provided by XNA Game Studio.

Next post:

Previous post: