Export (0) Print
Expand All

How To: Create and Use a Custom Vertex

This example demonstrates how to create a custom vertex and use it to render a 3D primitive object. It extends the concepts discussed in How To: Use BasicEffect and How To: Draw Points, Lines, and Other 3D Primitives.

A custom vertex can include any standard and custom data types. This allows you to provide functionality beyond the standard XNA Framework vertex declarations; such as VertexPositionColor.

This topic illustrates this concept with a custom vertex (of type VertexPositionColoredNormal) with three properties: a Vector3 position, a Color color, and a Vector3 normal. With this information, you can render 3D primitives with basic color and lighting effects.

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.

Declaring the Custom Vertex

The requirements for a custom vertex are:

  • Properties, implemented using both standard and user-defined data types, containing the values for the custom vertex. For this example, three properties are declared representing the position, color, and normal of the vertex.
  • A public method called SizeInBytes.
  • An array of type VertexElement with each element representing a property of the custom vertex. For this example, the properties are represented by two Vector3 types and a Color type.

In addition, you can implement some standard methods, such as constructors and public property accessors. For this example, a constructor and public methods for the three properties are implemented.

To declare the custom vertex

  1. At the top of the source file declaring your game class, declare a structure containing the necessary components, based on the requirements listed above.

    This part of the structure declaration declares a custom vertex with properties for the position, color, and vertex normal.

        Vector3 vertexPosition;
        Color vertexColor;
        Vector3 vertexNormal;
    
        public static int SizeInBytes { get { return 24; } }
    
        //Declares the elements of the custom vertex. Each vertex stores information on the current 
        //position, color, and normal.
        public static readonly VertexElement[] VertexElements = new VertexElement[]
    {
       new VertexElement(0, 0, VertexElementFormat.Vector3,
        VertexElementMethod.Default, VertexElementUsage.Position, 0),
       new VertexElement(0, sizeof(float) * 3, VertexElementFormat.Color,
        VertexElementMethod.Default, VertexElementUsage.Color, 0),
       new VertexElement(0, sizeof(float) * 3 + 4, VertexElementFormat.Vector3,
        VertexElementMethod.Default, VertexElementUsage.Normal, 0),
    };
    
  2. Declare any additional methods you think are necessary.

    This part of the structure declaration declares a constructor and three public methods (for each custom vertex property).

    public VertexPositionColoredNormal(Vector3 pos, Color color, Vector3 normal)
    {
        vertexPosition = pos;
        vertexColor = color;
        vertexNormal = normal;
    }
    
    //Public methods for accessing the components of the custom vertex.
    public Vector3 Position { get { return vertexPosition; } set { vertexPosition = value; } }
    public Color Color { get { return vertexColor; } set { vertexColor = value; } }
    public Vector3 Normal { get { return vertexNormal; } set { vertexNormal = value; } }
    

The custom vertex structure declaration is now complete. Initializing the basic effect is next.

Initializing the Effect and Camera

The next step initializes an effect (of type BasicEffect) and the related camera. These are used for basic coloring and lighting effects and for viewing the 3D object. Although this step is not strictly necessary for implementing a custom vertex, it is provided to illustrate a common usage scenario for this custom vertex; the rendering of a simple 3D object with color and light effects.

To initialize the basic effect and camera

  1. Declare variables for the basic effect and various projection matrices.

    BasicEffect basicEffect;
    Matrix worldMatrix;
    Matrix viewMatrix;
    Matrix projectionMatrix;
    
  2. Initialize the matrices of the camera object.

    In this topic, a translation matrix is created to place the primitive at the center of the viewport of the game, and the camera is oriented to look at (0, 0, 0) from a short distance away.

    //Centers the triangle strip in the game's viewport.
    worldMatrix = Matrix.CreateTranslation(-1.5f, -0.5f, 0.0f);
    
    viewMatrix = Matrix.CreateLookAt(
        new Vector3(0.0f, 0.0f, 5.0f),
        Vector3.Zero,
        Vector3.Up
        );
    
    projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
        MathHelper.ToRadians(45),
        (float)graphics.GraphicsDevice.Viewport.Width / (float)graphics.GraphicsDevice.Viewport.Height,
        1.0f, 100.0f
        );
    
  3. Initialize the effect to display a colored 3D primitive with default lighting.

    In this topic, vertex coloring and lighting are enabled. In addition, the default lighting scenario is used to light the primitive. This is the minimum needed to properly color and light the primitive.

    basicEffectVertexDeclaration = new VertexDeclaration(
        graphics.GraphicsDevice, VertexPositionColoredNormal.VertexElements);
    
    //Enables some basic effect characteristics, such as vertex coloring an ddefault lighting.
    basicEffect = new BasicEffect(graphics.GraphicsDevice, null);
    basicEffect.VertexColorEnabled = true;
    basicEffect.LightingEnabled = true;
    basicEffect.EnableDefaultLighting();
    
    basicEffect.World = worldMatrix;
    basicEffect.View = viewMatrix;
    basicEffect.Projection = projectionMatrix;
    

This completes the initialization of the camera and basic effect. The next step sets up a basic triangle strip using the custom vertex declared earlier in this topic.

Initializing the 3D Primitive

In this step, a vertex array is initialized with custom vertices implemented by VertexPositionColoredNormal. The vertex array, in addition to an indices array, is used later to render a colored triangle strip with default lighting effects.

To initialize the triangle strip

  1. Declare an array (of type VertexPositionColoredNormal), and initialize the various properties of the vertex elements. In this topic, a triangle strip (from 0,0 to 3,0 and on the plane z = 0) is drawn.

    triangleStripVertices = new VertexPositionColoredNormal[8];
    
    //Initialize the custom vertex values for the triangle strip.
    for (int x = 0; x < 4; x++)
    {
        for (int y = 0; y < 2; y++)
        {
            triangleStripVertices[(x * 2) + y] = new VertexPositionColoredNormal(
                new Vector3(x, y, 0.0f),
                Color.Red,
                new Vector3(0.0f, 0.0f, 1)
                );
        }
    }
    
  2. Create and initialize the indices buffer for the primitive. Because a triangle strip is being used, the buffer is relatively small.

    triangleStripIndices = new short[8];
    for (int i = 0; i < 8; i++)
    {
        triangleStripIndices[i] = (short)i;
    }
    

Initialization of the triangle strip is complete and the final step, rendering the triangle strip, is next.

Drawing the 3D Primitive

In this step, a red triangle strip is rendered with some basic lighting effects. This code is commonly placed inside the Draw method of your game.

To draw the triangle strip

  1. Declare the proper vertex declaration for the graphics device and call the DrawUserIndexedPrimitives method.

    graphics.GraphicsDevice.VertexDeclaration = basicEffectVertexDeclaration;
    
    basicEffect.Begin();
    foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
    {
        pass.Begin();
    
        graphics.GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColoredNormal>(
            PrimitiveType.TriangleStrip,
            triangleStripVertices,
            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
        );
    
        pass.End();
    }
    basicEffect.End();
    

These simple lighting effects are the reason the VertexPositionColoredNormal custom vertex type was created. Because each vertex has a normal, along with a position and color, the basic effect determines where the triangle strip is highlighted and where any shadows lie. If you had instead used vertices, of type VertexPositionColor, there would be no normals to determine any lighting effects.

Community Additions

ADD
Show:
© 2014 Microsoft