How To: Draw Points, Lines, and Other 3D Primitives

How To: Draw Points, Lines, and Other 3D Primitives

In the XNA Framework, a 3D primitive is a special type of 3D shape that describes how the graphics device interprets vertices stored in a vertex array or vertex stream. This example demonstrates how to use the point, line, and triangle primitive types that are the basis for all low-level drawing calls in the XNA Framework.
Bb196414.note(en-US,XNAGameStudio.20).gifNote
To render primitives, it is necessary to create a basic effect and several transformation matrices. This topic follows the steps described in How To: Use BasicEffect to create an instance of BasicEffect. This sample uses perspective projection but primitives can also be rendered using orthographic presentation. For more information, see the CreateOrthographic Method topic.

The vertices used in the sample are of type VertexPositionNormalTexture Structure. Vertices of this type contain position, normal data, and one set of texture coordinates. For this sample, only the position information is used.

The Complete Sample

The code in this tutorial illustrates the technique described in the text. A complete code sample for this tutorial is available for you to download, including full source code and any additional supporting files required by the sample.

The major steps for this example are listed below:

Drawing Points

To draw a point list

  1. Create a list of vertices in 3D space that represent the points to draw.

    pointList = new VertexPositionNormalTexture[points];
    
    for (int x = 0; x < points / 2; x++)
    {
        for (int y = 0; y < 2; y++)
        {
            pointList[(x * 2) + y] = new VertexPositionNormalTexture(
                new Vector3(x, y, 0),
                Vector3.Forward,
                Vector2.One
                );
        }
    }
    

    In this topic, eight points forming a triangle strip consisting of six triangles are drawn along the plane z = 0 and centered around (0, 0, 0). The camera is positioned at (0, 0, 7) looking at (0, 0, 0). This results in a orthogonal view of all eight points. The positioning of the points, the camera, and the required transformations are implemented with the following code:

    worldMatrix = Matrix.CreateTranslation(new Vector3(-1.5f, -0.5f, 0.0f));
    
    viewMatrix = Matrix.CreateLookAt(
        new Vector3(0.0f, 0.0f, 7.0f),
        new Vector3(0.0f, 0.0f, 0.0f),
        Vector3.Up
        );
    
    projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
        MathHelper.ToRadians(45),
        (float)graphics.GraphicsDevice.Viewport.Width /
        (float)graphics.GraphicsDevice.Viewport.Height,
        1.0f, 100.0f
        );
    

    The following code initializes these eight points and stores them in an array of type VertexPositionNormalTexture. This results in an array with the following vertex positions.

    Bb196414.DrawPrimitives1(en-US,XNAGameStudio.20).jpg
  2. The size of a point rendered from a point list is controlled by setting the property RenderState.PointSize. Here, the point size is specified as 10, so at each point in the list a 10-pixel square is drawn.

    graphics.GraphicsDevice.RenderState.PointSize = 10;
    
  3. Render the points by calling DrawUserPrimitives, specifying PrimitiveType.PointList to determine how the data in the vertex array is interpreted.

    graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionNormalTexture>(
        PrimitiveType.PointList,
        pointList,
        0,  // index of the first vertex to draw
        8   // number of primitives
    );
    

Drawing Lines

To draw a line list

  1. This example uses the sample vertex list created in step 1 of "To draw a point list". Here, an index array is created that indexes into that vertex buffer, identifying a series of lines.

    // Initialize an array of indices of type short.
    lineListIndices = new short[(points * 2) - 2];
    
    // Populate the array with references to indices in the vertex buffer
    for (int i = 0; i < points - 1; i++)
    {
        lineListIndices[i * 2] = (short)(i);
        lineListIndices[(i * 2) + 1] = (short)(i + 1);
    }
    

    This is equivalent to setting lineListIndices to the following array, consisting of a series of lines between pointList[0] and pointList[1], pointList[1] and pointList[2], and so forth.

    lineListIndices = new short[14]{ 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7 };
    
  2. Render the lines by calling DrawUserIndexedPrimitives, specifying PrimitiveType.LineList to determine how to interpret the data in the vertex array.

    graphics.GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(
        PrimitiveType.LineList,
        pointList,
        0,  // vertex buffer offset to add to each element of the index buffer
        8,  // number of vertices in pointList
        lineListIndices,  // the index buffer
        0,  // first index element to read
        7   // number of primitives to draw
    );
    

Drawing a Line Strip

To draw a line strip

This example uses the same point list and renders the same output as "To draw a line list", but it uses a line strip primitive type when identifying the indices of the vertex array to draw. Because a line strip is used, fewer indices are stored.

  1. Create a list of indices identifying the order in which to draw the points in the specified point list. Here, you need only half the number of indices as were used for the line list because the data consists of a series of connected lines.

    // Initialize an array of indices of type short.
    lineStripIndices = new short[points];
    
    // Populate the array with references to indices in the vertex buffer.
    for (int i = 0; i < points; i++)
    {
        lineStripIndices[i] = (short)(i);
    }
    

    This is equivalent to setting lineStripIndices to the following array, consisting of a series of connected lines between pointList[0], pointList[1], and pointList[2], and so forth.

    lineStripIndices = new short[8]{ 0, 1, 2, 3, 4, 5, 6, 7 };
    
  2. Render the line strip by calling DrawUserIndexedPrimitives, specifying PrimitiveType.LineStrip to determine how the data in the vertex array is interpreted. Note that fewer vertices are used to render the same number of primitives rendered earlier by the line list.

    Bb196414.note(en-US,XNAGameStudio.20).gifNote
    In the example code, the line strip is rendered by a series of red lines, instead of the white lines used for the previous line list. This is used to indicate a different primitive type even though the result is the same.
    basicEffect.DiffuseColor = new Vector3(1.0f, 0.0f, 0.0f);
    basicEffect.CommitChanges();
    
    graphics.GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(
        PrimitiveType.LineStrip,
        pointList,
        0,   // vertex buffer offset to add to each element of the index buffer
        8,   // number of vertices to draw
        lineStripIndices,
        0,   // first index element to read
        7    // number of primitives to draw
    );
    basicEffect.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f);
    basicEffect.CommitChanges();
    

Drawing Triangles

To draw a triangle list

Like a line list, a triangle list is a primitive type indicating that the vertices in the vertex buffer are to be interpreted as a series of separately drawn triangles.

  1. Create an array to hold the list of indices identifying a series of triangles to draw from the specified point list.

    triangleListIndices = new short[(width - 1) * (height - 1) * 6];
    
    for (int x = 0; x < width - 1; x++)
    {
        for (int y = 0; y < height - 1; y++)
        {
            triangleListIndices[(x + y * (width - 1)) * 6] = (short)(2 * x);
            triangleListIndices[(x + y * (width - 1)) * 6 + 1] = (short)(2 * x + 1);
            triangleListIndices[(x + y * (width - 1)) * 6 + 2] = (short)(2 * x + 2);
    
            triangleListIndices[(x + y * (width - 1)) * 6 + 3] = (short)(2 * x + 2);
            triangleListIndices[(x + y * (width - 1)) * 6 + 4] = (short)(2 * x + 1);
            triangleListIndices[(x + y * (width - 1)) * 6 + 5] = (short)(2 * x + 3);
        }
    }
    

    This is equivalent to setting triangleListIndices to the following array, consisting of a series of triangles between pointList[0], pointList[1], and pointList[2], and so forth.

    triangleListIndices = new short[18]{ 0, 1, 2, 2, 1, 3, 2, 3, 4, 4, 3, 5, 4, 5, 6, 6, 5, 7 };
    
  2. Render the lines by calling DrawUserIndexedPrimitives, specifying PrimitiveType.TriangleList to determine how the data in the vertex array is interpreted.

    graphics.GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(
        PrimitiveType.TriangleList,
        pointList,
        0,   // vertex buffer offset to add to each element of the index buffer
        8,   // number of vertices to draw
        triangleListIndices,
        0,   // first index element to read
        6    // number of primitives to draw
    );
    

Drawing a Triangle Strip

To draw a triangle strip

A triangle strip is a set of triangles that share multiple vertices. This example shows how to render an object that looks the same as the object rendered with a triangle list, but with fewer vertices needed—because the triangles share multiple vertices.

  1. Create an array to hold the list of indices identifying a strip of triangles.

    // Initialize an array of indices of type short.
    triangleStripIndices = new short[points];
    
    // Populate the array with references to indices in the vertex buffer.
    for (int i = 0; i < points; i++)
    {
        triangleStripIndices[i] = (short)i;
    }
    

    This is equivalent to setting triangleStripIndices to the following array, consisting of a series of connected triangles between pointList[0], pointList[1], and pointList[2], and so forth.

    triangleStripIndices = new short[8]{ 0, 1, 2, 3, 4, 5, 6, 7 };
    
  2. Render the lines by calling DrawUserIndexedPrimitives, specifying PrimitiveType.TriangleStrip to determine how the data in the vertex array is interpreted. Note that fewer vertices are used to render the same number of primitives rendered earlier by the triangle list.

    Bb196414.note(en-US,XNAGameStudio.20).gifNote
    In the example code, the triangle strip is rendered by a series of red lines, instead of the white lines used for the previous triangle list. This is used to indicate a different primitive type even though the result is the same.
    basicEffect.DiffuseColor = new Vector3(1.0f, 0.0f, 0.0f);
    basicEffect.CommitChanges();
    
    graphics.GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(
        PrimitiveType.TriangleStrip,
        pointList,
        0,  // vertex buffer offset to add to each element of the index buffer
        8,  // number of vertices to draw
        triangleStripIndices,
        0,  // first index element to read
        6   // number of primitives to draw
    );
    basicEffect.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f);
    basicEffect.CommitChanges();
    

Community Additions

ADD
Show:
© 2016 Microsoft