Vertices and Indices can sound like something
really complex and difficult when you are first starting out in 3D.
Further complicating things is the enormous number of options
surrounding vertices and indices. So, I thought it might be useful to
spend some time on the topic. The singular form of the words vertices
and indices is vertex and index.
Let’s start by taking a look as vertices. When you
first get into 3D, a vector, a point, and a vertex all seem like the
same thing. All 3 have points, or
positions, in 3D space. They are not the same thing at all, although you
may see them treated similarly from time to time. This is because they
all have a point, or position.
Everything in your 3D world will be drawn using
either lines or triangles. XNA calls lines and triangles “primitives”. A
lot of times you will hear triangles referred to as polygons or simply
“polys”. But everything you see on the screen is made from triangles. In
DX11, even sprites are drawn using triangles and I suspect that XNA does
this behind the scenes with sprites. The way these triangles are defined
is by 3 points called “vertices”. Now, I just said that a vertex is not
a point. That’s true. But, all vertices
have a position. They
have much more than that though and that is the distinction.
So, 3 vertices define a triangle. You can start by
thinking of them as the positions of the corners of the triangle,
although this is a bit of an oversimplification.
Vertices can also be used to define the two points
that a line draws between when drawing lines.
But, it is important to know that vertices almost
always contain additional data. For example, each vertex can have a
color. For a line, this will mean that the line will start with one
color and change to the other color as it gets closer to the second
vertex and its color.
For a triangle, if all 3 vertices have separate
colors, you will get a mix of all 3 colors where the color becomes more
pure nearer its vertex.
There is another way to “paint” the triangles of
your object that is almost always used instead of just paintings
vertices with color. This method of painting triangles is known as
“texturing,” Texturing basically paints a “texture”, or photograph,
across the surface of the triangle and is the primary way that things
are “painted” in 3D games these days. The texture is mapped, or
attached, to the triangles at the vertices with what is called “UV”
coordinates. These UV coordinates are also part of the vertex.
Basically, they “pin” the part of the image at the UV coordinate (XY
position in the picture) to the vertex. And the picture then stretches
between vertices according to the UV coordinates.
A vertex may also contain additional information a
normal, a tangent, or other data. In fact, you can even define your own
custom vertex format. Normals are used for lighting calculations and
basically specify what direction the vertex is “facing”.
And now may be a good time to mention vertex
“winding”. Often, it is very
important to know which direction a triangle is facing. The way this is
determined is by the order that the vertices are defined in (or indexed
in). If they are defined in clockwise order, the triangle will point one
way and if they are in counter clockwise order the triangle will face
the other way. This order the vertices are defined in is called their
“winding”.
But, starting out, you can think of vertices mostly
as the corner positions of the triangles that compose all of your
objects, as long as you understand that they contain a lot more data
than that.
You “could” define all your objects just using
vertices alone. But you quickly find that a lot of triangles in your
objects share vertices. For example, think about a cube. Each square
face of the cube will be made up of two triangles. There are 6 faces and
each face is 2 triangles. So, that’s 12 triangles in a cube. And if each
is defined by 3 vertices, then that’s 36 vertices.
But notice that every corner is one position but if
every triangle is made up of 3 vertices, then a single corner will have
several vertices that are all redundant. There are only 8 corners. So
why does it take 36 vertices to define those corners? That’s 28 vertices
more than what you “should” need. And this is still one of the most
simple game objects you can have. Can you imagine an object with 10
million vertices and 9 million of them are basically the same vertex?
When you consider all the data in these vertices, you can see that they
could easily be 20 bytes in size each. So, 9 million wasted vertices
would be 180MB just wasted
in one object.
And this is where indices come in. Indices allow
you to specify what order your vertices get drawn in. This allows you to
draw them out of order, but more importantly it means that we only need
8 vertices for our cube and then we can use indices to draw all the
triangles of the cube. And an index is just an integer. Each index is
considerably smaller
than a vertex. And that means substantially less memory used up by your
object because it only needs 1 million vertices instead of 10 million
and the indices that replaced each vertex are a fraction of the memory
used.
With indices, you’re basically just specifying the
order of the vertices.
With a Triangle List draw (drawing triangles as a
list of triangles) you just specify the vertices in order, as if you
were drawing the lines, or edges, of the triangles. So a square might be
something like 0,1,2, 2,3,0 for the indices. 0,1,2 defines a triangle in
clockwise order (presumably) and 2,3,0 defines another triangle in
clockwise order. So, that would be "Draw from vertex 0 to 1 to 2
(triangle) and draw from vertex 2 to 3 to 0 (triangle). But notice the
second triangle doubles back and uses two of the vertices from the first
triangle. And that makes sense since the two triangles share two
vertices when they form a square.
A Triangle
Strip will also use indices, but instead of using the indices
to specify triangles, it assumes that you will always use the previous
two indices. So, once you draw your first triangle
every vertex results
in a triangle after that. So, triangle strips make indices even
more efficient.
And that’s basically all there is to vertices and
indices.
You generally define them in arrays of vertices and
integers (for indices). You could call DrawUserPrimitives() to draw just
using vertices. Or you could call DrawUserIndexedPrimitives() to draw
using indices. However, you can also store this data on the graphics
card and call it from there to make it more efficient. To do that, you
would use DrawIndexedPrimitives() or DrawPrimitives(). If you are going
to do this, however, you have to transfer the vertices and indices to a
buffer and send that data to the graphics card, which is another step or
two.
One last thing that people may be confused by
starting out: XNA has a model class that you can use to draw models.
Internally, this is also using vertices and indices. However, the model
class manages all that data for you. In fact, in order to draw a model,
you just tell every mesh within the model to draw itself. So, there’s no
vertices, indices, or mess. They just simply know how to draw
themselves. They are using vertices and indices (and are made up of
triangles) too, you just don’t have to deal with them.
Vertices and Indices may sound like something really complicated, but in fact they are fairly straight forward. Think of vertices as the corners of the triangles that make up every object drawn on the screen. And think of indices as the order the vertices are drawn in.
Here we examine them in more detail.