|
| 1 | +--- |
| 2 | +title: How to create a Custom Vertex Declaration |
| 3 | +description: Demonstrates how to create a custom vertex declaration and use it to render a 3D object. |
| 4 | +requireMSLicense: true |
| 5 | +--- |
| 6 | + |
| 7 | +## Overview |
| 8 | + |
| 9 | +MonoGame includes a few predefined classes for common vertex buffer declarations such as [VertexPositionColor](xref:Microsoft.Xna.Framework.Graphics.VertexPositionColor) and [VertexPositionColorTexture](xref:Microsoft.Xna.Framework.Graphics.VertexPositionColorTexture). If you need to create a vertex buffer declaration that includes additional user-defined types, create a custom vertex declaration. |
| 10 | + |
| 11 | + |
| 12 | + |
| 13 | +A custom vertex declaration is a class that implements fully customizable per-vertex data. Furthermore, if you derive the class from [IVertexType](xref:Microsoft.Xna.Framework.Graphics.IVertexType), you will not need to create a vertex declaration when creating your vertex buffer or drawing the geometry. |
| 14 | + |
| 15 | +## Requirements |
| 16 | + |
| 17 | +The following texture will be used to render to the screen. |
| 18 | + |
| 19 | + |
| 20 | + |
| 21 | +Save it to your content project and name it "**logo**" (this name will used to reference it in the project). Make sure to [add it to your content project](../content_pipeline/HowTo_GameContent_Add.md). |
| 22 | + |
| 23 | +## Starting from the [Basic Effect](HowTo_Create_a_BasicEffect.md) tutorial |
| 24 | + |
| 25 | +1. Follow the steps of [How to create a Basic Effect](HowTo_Create_a_BasicEffect.md). |
| 26 | + |
| 27 | + This gives us a starting project that is rendering a 3D scene with a [Basic Effect](xref:Microsoft.Xna.Framework.Graphics.BasicEffect). |
| 28 | + |
| 29 | +## Create a custom vertex declaration |
| 30 | + |
| 31 | +1. Create a new class file called `CustomVertex1.cs` |
| 32 | + |
| 33 | +1. Add the required `using` statements to the top of the file. |
| 34 | + |
| 35 | + ```csharp |
| 36 | + using Microsoft.Xna.Framework; |
| 37 | + using Microsoft.Xna.Framework.Graphics; |
| 38 | + ``` |
| 39 | + |
| 40 | +1. Declare a structure that derives from [IVertexType](xref:Microsoft.Xna.Framework.Graphics.IVertexType). |
| 41 | + |
| 42 | + ```csharp |
| 43 | + public struct CustomVertex1 : IVertexType |
| 44 | + ``` |
| 45 | + |
| 46 | +1. Add members to the struct that describe the per-vertex data. |
| 47 | + |
| 48 | + This example uses position as a [Vector3 Structure](xref:Microsoft.Xna.Framework.Vector3) type, a texture coordinate using a [Vector2 Structure](xref:Microsoft.Xna.Framework.Vector2) type, and a vertex declaration using the [VertexDeclaration](xref:Microsoft.Xna.Framework.Graphics.VertexDeclaration) type. |
| 49 | + |
| 50 | + ```csharp |
| 51 | + private Vector3 vertexPosition; |
| 52 | + private Vector2 vertexTextureCoordinate; |
| 53 | + |
| 54 | + public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration |
| 55 | + ( |
| 56 | + new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0), |
| 57 | + new VertexElement(12, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0) |
| 58 | + ); |
| 59 | + ``` |
| 60 | + |
| 61 | +1. Implement the constructor and public accessor methods. |
| 62 | + |
| 63 | + ```csharp |
| 64 | + //The constructor for the custom vertex. This allows similar |
| 65 | + //initialization of custom vertex arrays as compared to arrays of a |
| 66 | + //standard vertex type, such as VertexPositionColor. |
| 67 | + public CustomVertex1(Vector3 pos, Vector2 textureCoordinate) |
| 68 | + { |
| 69 | + vertexPosition = pos; |
| 70 | + vertexTextureCoordinate = textureCoordinate; |
| 71 | + } |
| 72 | + |
| 73 | + //Public methods for accessing the components of the custom vertex. |
| 74 | + public Vector3 Position |
| 75 | + { |
| 76 | + get { return vertexPosition; } |
| 77 | + set { vertexPosition = value; } |
| 78 | + } |
| 79 | + |
| 80 | + public Vector2 TextureCoordinate |
| 81 | + { |
| 82 | + get { return vertexTextureCoordinate; } |
| 83 | + set { vertexTextureCoordinate = value; } |
| 84 | + } |
| 85 | + ``` |
| 86 | + |
| 87 | +1. Implement a non-public method for accessing the vertex declaration. |
| 88 | + |
| 89 | + ```csharp |
| 90 | + VertexDeclaration IVertexType.VertexDeclaration |
| 91 | + { |
| 92 | + get { return VertexDeclaration; } |
| 93 | + } |
| 94 | + ``` |
| 95 | + |
| 96 | +## Using the Custom Vertex Buffer |
| 97 | + |
| 98 | +Using the Custom Vertex buffer, we will render a cube that is textured with the logo texture. |
| 99 | + |
| 100 | +1. Declare some variables at the top of your Game class. |
| 101 | + |
| 102 | + ```csharp |
| 103 | + private CustomVertex1[] cubeVertices; |
| 104 | + private VertexBuffer vertexBuffer; |
| 105 | + private Texture2D logoTexture; |
| 106 | + ``` |
| 107 | + |
| 108 | + This gives us the necessary data in order to draw our cube. |
| 109 | + |
| 110 | +1. Create a new method called `SetupDrawingCube()` and we will start with initializing the vertex buffer, passing in the **typeof(CustomVertex1)** instead of a vertex declaration to describe the vertex buffer data. |
| 111 | + |
| 112 | + ```csharp |
| 113 | + public void SetupDrawingCube() |
| 114 | + { |
| 115 | + vertexBuffer = new VertexBuffer( |
| 116 | + GraphicsDevice, |
| 117 | + typeof(CustomVertex1), |
| 118 | + 36, |
| 119 | + BufferUsage.None |
| 120 | + ); |
| 121 | + ``` |
| 122 | + |
| 123 | +1. Create the per-vertex data; this shows a portion of the code. |
| 124 | + |
| 125 | + [!code-csharp[](./files/cubevertexdata.cs)] |
| 126 | + |
| 127 | + > For a triangle list, you need three vertices for a triangle and two triangles to make the front face of a cube. |
| 128 | + |
| 129 | +1. Finally, set the data into the vertex buffer data by calling [VertexBuffer.SetData](xref:Microsoft.Xna.Framework.Graphics.VertexBuffer) and set the vertex buffer to the device by calling [GraphicsDevice.SetVertexBuffer](xref:Microsoft.Xna.Framework.Graphics.GraphicsDevice). |
| 130 | + |
| 131 | + ```csharp |
| 132 | + vertexBuffer.SetData<CustomVertex1>(cubeVertices); |
| 133 | + |
| 134 | + graphics.GraphicsDevice.SetVertexBuffer(vertexBuffer); |
| 135 | + } |
| 136 | + ``` |
| 137 | + |
| 138 | +1. In `LoadContent` we need to Load the texture we are going to draw, as well as call the new method we defined to setup the primitive Cube. |
| 139 | + |
| 140 | + ```csharp |
| 141 | + logoTexture = Content.Load<Texture2D>("logo"); |
| 142 | + SetupDrawingCube(); |
| 143 | + ``` |
| 144 | + |
| 145 | +1. At the moment the `BasicEffect` setup from the previous tutorial only draws Vertex Colors, so we need to change that to pass it the [texture](xref:Microsoft.Xna.Framework.Graphics.BasicEffect#Microsoft_Xna_Framework_Graphics_BasicEffect_Texture) we just loaded, as well as enabling [Texture drawing](xref:Microsoft.Xna.Framework.Graphics.BasicEffect#Microsoft_Xna_Framework_Graphics_BasicEffect_TextureEnabled) |
| 146 | + |
| 147 | + Replace: |
| 148 | + |
| 149 | + ```csharp |
| 150 | + basicEffect.VertexColorEnabled = true; |
| 151 | + ``` |
| 152 | + |
| 153 | + With the following |
| 154 | + |
| 155 | + ```csharp |
| 156 | + // Enable Texture Drawing - VERY IMPORTANT!! |
| 157 | + basicEffect.TextureEnabled = true; |
| 158 | + |
| 159 | + // Set the texture we loaded (does nothing without the above setting) |
| 160 | + basicEffect.Texture = logoTexture; |
| 161 | + ``` |
| 162 | + |
| 163 | +1. Finally, Draw the object by calling [GraphicsDevice.DrawPrimitives](xref:Microsoft.Xna.Framework.Graphics.GraphicsDevice). |
| 164 | + |
| 165 | + ```csharp |
| 166 | + foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes) |
| 167 | + { |
| 168 | + pass.Apply(); |
| 169 | + |
| 170 | + graphics.GraphicsDevice.DrawPrimitives( |
| 171 | + PrimitiveType.TriangleList, |
| 172 | + 0, // start vertex |
| 173 | + 12 // number of primitives to draw, 2 vertexes per side of the cube |
| 174 | + ); |
| 175 | + } |
| 176 | + ``` |
| 177 | + |
| 178 | +## Extra credit, make it spin |
| 179 | + |
| 180 | +At the moment all you can see is the front face of the cube, which is not very exciting. Though [Matrix Transforms](HowTo_TransformPoint.md) however, we make our cube spin. |
| 181 | + |
| 182 | +1. First define a variable to manage the current rotation. |
| 183 | + |
| 184 | + ```csharp |
| 185 | + float rotation = 0f; |
| 186 | + ``` |
| 187 | + |
| 188 | +1. Next, we will update this rotation each frame in the `Update` method. |
| 189 | + |
| 190 | + ```csharp |
| 191 | + // Update rotation angle |
| 192 | + float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; |
| 193 | + rotation += deltaTime; |
| 194 | + ``` |
| 195 | + |
| 196 | +1. Then finally, in the `Draw` method, we need to calculate the rotation matrix and the translation matrix to rotate the cube by and then apply that to the basic effect drawing the cube. |
| 197 | + |
| 198 | + Add the following to the `Draw` call **BEFORE** the effect drawing loop. |
| 199 | + |
| 200 | + ```csharp |
| 201 | + // Create rotation matrices |
| 202 | + Matrix rotationMatrix = Matrix.CreateRotationX(rotation) * |
| 203 | + Matrix.CreateRotationY(rotation) * |
| 204 | + Matrix.CreateRotationZ(rotation); |
| 205 | + // Apply rotation to the world matrix |
| 206 | + Matrix worldMatrix = rotationMatrix * Matrix.CreateTranslation(new Vector3(0, 0, 0)); |
| 207 | + // Update the world matrix in the effect |
| 208 | + basicEffect.World = worldMatrix; |
| 209 | + ``` |
| 210 | + |
| 211 | +> [!NOTE] |
| 212 | +> This is a very basic example of applying rotation, just for reference. |
| 213 | + |
| 214 | +With the changes in place, your cube will look a little more snazzy and rotate in the world. |
| 215 | + |
| 216 | + |
| 217 | + |
| 218 | +## See Also |
| 219 | + |
| 220 | +- [How to create a Basic Effect](HowTo_Create_a_BasicEffect.md) |
| 221 | +- [How to transform a Point](HowTo_TransformPoint.md) |
| 222 | + |
| 223 | +### Concepts |
| 224 | + |
| 225 | +- [What Is 3D Rendering?](../../whatis/graphics/WhatIs_3DRendering.md) |
| 226 | + |
| 227 | +### Reference |
| 228 | + |
| 229 | +- [IVertexType](xref:Microsoft.Xna.Framework.Graphics.IVertexType) |
| 230 | +- [VertexDeclaration](xref:Microsoft.Xna.Framework.Graphics.VertexDeclaration) |
| 231 | +- [Matrix](xref:Microsoft.Xna.Framework.Matrix) |
0 commit comments