All the drawing in our examples has been handled by making a call to the GraphicsDevice.DrawUserPrimitives function. The first parameter passed to this function, the primitiveType parameter, has always been PrimitiveType.TriangleStrip. There are several values that we can pass here, so let's take a look at each and discuss what they do and how they are used.
1. Drawing Lines
There are two different mechanisms provided for drawing lines on the screen: PrimitiveType.LineList and PrimitiveType.LineStrip.
LineList will work through the supplied
vertices, taking each pair as the beginning and end coordinate of a
line. The lines do not need to be connected (and indeed, if they are it
might be more efficient to use the LineStrip drawing mode). The DrawUserPrimitiveprimitiveCount
parameter specifies how many lines are to be drawn. Because each line
requires two vertices, the vertex array must contain at least twice the
number of entries as the specified primitive count.
Figure 1 shows the lines drawn between four vertices using the LineList mode primitive type, and a primitive count of 2.
LineStrip is similar, but instead of
working through pairs of vertices, it takes each new vertex and draws a
line between it and the previous vertex. The result is a line drawn
betweenall the specified vertices, as shown in Figure 2.
The first line requires two vertices, but each subsequent line requires
just one more. As a result, the vertex array must contain at least primitiveCount + 1 elements.
XNA does not offer a line drawing mode that automatically reconnects the final vertex back to the first vertex (to create a line loop). If such rendering is required, a final additional vertex will need to be added to the end of the LineStrip whose position matches that of the first vertex.
You can easily see the effects of drawing lines by modifying the ColoredSquare project to use the line primitive types instead of its existing TriangleStrip
type. Notice how the vertex colors are still observed when drawing
lines, and the line color fades between the color of each connected
vertex.
There is no facility for setting the width of the
line: all lines will be drawn with single-pixel thickness. If you need
to draw lines thicker than this, you will need to simulate lines by
drawing long thin rectangles formed from a pair of triangles instead.
2. Drawing Triangles
The remaining drawing primitives provide two
different methods for creating triangles. Triangles are by far the most
common type of object drawn in XNA, so these primitive types will
become very familiar. The available triangle primitive modes are PrimitiveType.TriangleList and PrimitiveType.TriangleStrip.
The TriangleList primitive takes each set of three vertices as an individual triangle, allowing multiple isolated triangles to be drawn. Figure 3
shows how six vertices are used to build two triangles using this mode.
Because each triangle requires three vertices, the vertex array must
contain at least three times the number of entries as the specified
primitive count.
The TriangleStrip primitivereuses vertices
within the vertex array to create multiple triangles, each of which
shares an edge with the previous triangle. The first three vertices are
used to create the first triangle; after that, the next triangle is
formed by removing the earliest vertex in the triangle and replacing it
with the next vertex. The first triangle is, therefore, formed from
vertices 0, 1, and 2; the second triangle from vertices 1, 2, and 3;
the third triangle from vertices 2, 3, and 4; and so on.
As long as you can arrange your triangles so that
they share their edges in this way, the triangle strip is a very
efficient way of drawing because the shared vertices need to be
transformed only once even though they are used by as many as three
different triangles.
Figure 4 shows an example using the TriangleStrip
to join a series of vertices.The first triangle requires three
vertices, but each subsequent triangle requires just one more. As a
result, the vertex array must contain at least primitiveCount + 2 elements.
The TriangleStrip mode is perfectly suited
for drawing squares and rectangles because they are formed from two
triangles that share an edge. As more complex objects are encountered,
however, the ability to model them using triangle strips soon becomes
difficult or impossible, and for them a triangle list will be required
instead.
If you have used earlier versions of XNA or are
familiar with DirectX or OpenGL, you might be expecting to find a
further primitive type known as a triangle fan.
It defines a series of triangles that all share a single vertex,
allowing that vertex to be calculated just once for the entire object.
Support for triangle fans was removed in XNA version 4.0 (as used on
Windows Phone 7), so this primitive type is no longer available for use.
When you are defining your triangles, you will need to be aware of XNA's hidden surface culling. This is a feature that prevents it from having to draw unnecessary triangles.
For triangle strips, however, this would appear to
present a problem: as each triangle shares its vertices with the
previous triangle, the points alternate between clockwise and
counterclockwise order. This can be seen in Figure 4:
the first triangle (consisting of vertices 0, 1, and 2) is defined in
clockwise order, but the second (vertices 1, 2, and 3) is
counterclockwise. XNA realizes this and takes it into account
automatically; the important thing is to ensure that the first triangle in a triangle strip is defined in a clockwise direction.
3. Drawing Points
Unlike earlier versions of XNA, support for drawing
points (individual pixels) to the screen using vertices has been
removed. To simulate drawing points, you will need to instead draw very
small triangles, rectangles or lines.
Generally point drawing is of limited use anyway, so this will hopefully not present too much of a problem for your games.