XNA for C#
DirectX 9 for C#
DirectX 9 for C++
DirectX 9 for VB
Forum
   2D Series finished!
My Book: Out Now!
      
       Go to section on this site

Additional info


Latest Forum posts

 error x3000:syntax error
  Posted by: Anonymous
  When: 02/09/2010 at 06:55:17

 Reflection problem in corners ...
  Posted by: Anonymous
  When: 31/08/2010 at 20:53:30

 OcTree Question
  Posted by: radulph
  When: 31/08/2010 at 18:00:04

 model problems
  Posted by: Archenon
  When: 30/08/2010 at 05:54:27

 Changing computer breaks my game
  Posted by: Archenon
  When: 30/08/2010 at 05:49:50

 model problems
  Posted by: muffinman
  When: 28/08/2010 at 16:58:10

 Vertices problem
  Posted by: Anonymous
  When: 27/08/2010 at 15:35:36

 Changing computer breaks my game
  Posted by: radulph
  When: 27/08/2010 at 07:12:24

 effects file and XNA 4.0 (Beta)
  Posted by: radulph
  When: 26/08/2010 at 06:33:33

 Changing computer breaks my game
  Posted by: radulph
  When: 26/08/2010 at 06:27:59


Ads

Defining our own vertex format

Let’s have a look at the staring point in our flowchart: the big arrow starting in our XNA app, going to our vertex shader:



It represents the flow of vertex data from our XNA app to the vertex shader on the graphics card. This is triggered every time we issue some kind of draw command in XNA. When we pass the vertex data from our XNA app to our vertex shader, we need to pass some information with it, describing what kind of data is contained in the vertex stream. Using shaders, you need to specify exactly what information can be found in the stream, and where.

So what we need is:
  • a structure that can hold the necessary data for each vertex and
  • a definition of the data, so the vertex shader knows which data is included with every vertex.

    In the starting code, we’ve been using the VertexPositionColor struct which satisfies both requirements. Here, we’re going to define a new struct, MyOwnVertexFormat, that will be exactly the same as the VertexPositionColor struct, to see what’s in there and why it is needed. This will allow us to expand it further on in this series.

    For a far more detailed explanation on creating custom vertex formats, read Recipe 5-14.

    To satisfy the 2 requirements, in the example of a simple colored triangle, we need our vertices to hold 3D Position data as well as Color data. So this is how we start our struct (you can put this at the top of our code):

     struct MyOwnVertexFormat
     {
         private Vector3 position;
         private Color color;
     
         public MyOwnVertexFormat (Vector3 position, Color color)
         {
             this.position = position;
             this.color = color;
         }
     }

    We simply defined a new structure, and defined it so it can hold a vector3 and a color. We also defined a constructor, so later in our program we can create and fill a new instance of this struct in one line. The first requirement has been satisfied.

    Next, we need a way to tell our graphics card that the data we are sending actually contain Position and Color data. Although we gave the elements straightforward names (position, color), the graphics card needs to be told explicitly which data it will receive.

    As seen in the previous series, this is done by means of setting a VertexDeclaration before rendering triangle. However, when we created this VertexDeclaration, we always used the VertexElements property of the type of vertices we were rendering from. Since we are defining our own kind of vertices, we also need to define its VertexElements.

    The VertexElements property which will contain 1 entry for each type of data accompanying each vertex. Put this code inside, at the bottom of our struct:

     public static VertexElement[] VertexElements =
     {
         new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0),
         new VertexElement(0, sizeof(float)*3, VertexElementFormat.Color, VertexElementMethod.Default, VertexElementUsage.Color, 0),
     };
     public static int SizeInBytes = sizeof(float) * (3 + 1);

    For each type of data, we define how many bytes it occupies, what it is used for, and where it can be found. The following paragraph contains a brief summary of the explanation in Recipe 5-14.

    The first argument is the number of the vertexstream we’ll be describing. Because we’ll only be using one, we indicate 0. The second argument is very important. It indicates at which offset IN BYTES the type of data can found in the vertex stream. So the first type of data, the 3D position, starts at offset 0.

    Next, we indicate how that kind of data is stored, such as int, float1, short4 and more. A position comes in a Vector3 (which is composed of 3 floats). Concerning the next argument, you’ll almost always want to use DeclarationMethod.Default. The next argument is the most important one: it describes the kind of information, such as position, color, texture coordinate, tangent, etc. This is needed, so XNA can automatically link the right data from our vertex stream to the right variables in our vertex shaders.

    For the last argument, suppose you would like to add 2 textures to a triangle. This implicates you would have to pass 2 sets of texture coordinates along with each vector. For this, you can use the last argument, which is the index of each info. Since we’ll only be passing 1 position and 1 color for each vertex, this will be 0 for both lines.

    For our color, we do pretty much the same. It is still part of vertexstream 0, but because it is preceded by the position it can’t be found at offset 0. The position consists of 3 floats, this is what we need to indicate (a float occupies 4 bytes, so sizeof(float)*3 is 12, which is the offset in bytes to the color information). Although a color is in fact a Vector4 (4 floats: the RGBA values), we need to specify Color, because each value needs to be mapped within the range [0..1] before it can be passed to the vertex shader as a color. This is an exception.

    We also supply our MyOwnVertexFormat with a SizeInBytes member, which stores the number of bytes 1 vertex occupies in memory. Because the position uses 3 floats and the color 1 float, it will take up the memory of 4 floats, which is 16 bytes.

    Now let’s change our code so we’ll be using our MyOwnVertexFormat instead of the VertexPositionColor struct. Change our SetUpVertices to this:

     private void SetUpVertices()
     {
         MyOwnVertexFormat[] vertices = new MyOwnVertexFormat[3];
     
         vertices[0] = new MyOwnVertexFormat(new Vector3(-2, 2, 0), Color.Red);
         vertices[1] = new MyOwnVertexFormat(new Vector3(2, -2, -2), Color.Green);
         vertices[2] = new MyOwnVertexFormat(new Vector3(0, 0, 2), Color.Yellow);
     
         vertexBuffer = new VertexBuffer(device, vertices.Length * MyOwnVertexFormat.SizeInBytes, BufferUsage.WriteOnly);
         vertexBuffer.SetData(vertices);
     
         vertexDeclaration = new VertexDeclaration(device, MyOwnVertexFormat.VertexElements);        }

    Note that we have also adjusted our VertexDeclaration, so it corresponds to our newly defined type of vertex.

    We also should update the size of one vertex in the Draw method:

     device.Vertices[0].SetSource(vertexBuffer, 0, MyOwnVertexFormat.SizeInBytes);

    OK, we have recreated the pre-built VertexPositionColor struct. When you run the code, you should see the same triangle. Only this time, you know how what the VertexDeclaration contains and, more important, you know how to extend a vertex format. We will practice this in a later chapter.




    DirectX Tutorial 3 - Vertex format

    If you appreciate the amount of time I spend creating and updating
    these pages, feel free to donate -- any amount is welcome !



    Click here to go to the forum on this chapter!

    Or click on one of the topics on this chapter to go there:
  • Need light in my scene
          Hi everyone well i stoped folowing the chapter ca...
  • passing non-displayed data to the GPU?
          When I first had the idea of creating bones for an...
  • why float*3 instead of Vector3?
          Hey, In the static VertexElements we define an ...
  • Question about SizeInBytes Equation
          Hi - I had a question on some ambiguity I encounte...


    This is what the XNA code should look like, with the integration of our own vertex format:

     using System;
     using System.Collections.Generic;
     using Microsoft.Xna.Framework;
     using Microsoft.Xna.Framework.Audio;
     using Microsoft.Xna.Framework.Content;
     using Microsoft.Xna.Framework.GamerServices;
     using Microsoft.Xna.Framework.Graphics;
     using Microsoft.Xna.Framework.Input;
     using Microsoft.Xna.Framework.Net;
     using Microsoft.Xna.Framework.Storage;
     
     namespace XNAseries3
     {
         public class Game1 : Microsoft.Xna.Framework.Game
         {
             struct MyOwnVertexFormat
             {
                 private Vector3 position;
                 private Color color;
     
                 public MyOwnVertexFormat(Vector3 position, Color color)
                 {
                     this.position = position;
                     this.color = color;
                 }
     
                 public static VertexElement[] VertexElements =
                 {
                     new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0),
                     new VertexElement(0, sizeof(float)*3, VertexElementFormat.Color, VertexElementMethod.Default, VertexElementUsage.Color, 0),
                 };
     
                 public static int SizeInBytes = sizeof(float) * (3 + 1);
             }
     
             GraphicsDeviceManager graphics;
             GraphicsDevice device;
             
             Effect effect;
             Matrix viewMatrix;
             Matrix projectionMatrix;
             VertexBuffer vertexBuffer;
             VertexDeclaration vertexDeclaration;
             Vector3 cameraPos;
     
             public Game1()
             {
                 graphics = new GraphicsDeviceManager(this);            
                 Content.RootDirectory = "Content";
             }
     
             protected override void Initialize()
             {
                 graphics.PreferredBackBufferWidth = 500;
                 graphics.PreferredBackBufferHeight = 500;
                 graphics.IsFullScreen = false;
                 graphics.ApplyChanges();
                 Window.Title = "Riemer's XNA Tutorials -- Series 3";
     
                 base.Initialize();
             }
     
             protected override void LoadContent()
             {
                 device = GraphicsDevice;

                effect = Content.Load<Effect> ("effects");            SetUpVertices();
                SetUpCamera();
            }

            private void SetUpVertices()
            {

                 MyOwnVertexFormat[] vertices = new MyOwnVertexFormat[3];
     
                 vertices[0] = new MyOwnVertexFormat(new Vector3(-2, 2, 0), Color.Red);
                 vertices[1] = new MyOwnVertexFormat(new Vector3(2, -2, -2), Color.Green);
                 vertices[2] = new MyOwnVertexFormat(new Vector3(0, 0, 2), Color.Yellow);
     
                 vertexBuffer = new VertexBuffer(device, vertices.Length * MyOwnVertexFormat.SizeInBytes, BufferUsage.WriteOnly);
                 vertexBuffer.SetData(vertices);
     
                 vertexDeclaration = new VertexDeclaration(device, MyOwnVertexFormat.VertexElements);
             }
     
             private void SetUpCamera()
             {
                 cameraPos = new Vector3(0, 5, 6);
                 viewMatrix = Matrix.CreateLookAt(cameraPos, new Vector3(0, 0, 1), new Vector3(0, 1, 0));
                 projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 1.0f, 200.0f);
             }
     
             protected override void UnloadContent()
             {
             }
     
             protected override void Update(GameTime gameTime)
             {            
                 if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                     this.Exit();
     
                 base.Update(gameTime);
             }
     
             protected override void Draw(GameTime gameTime)
             {
                 device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.DarkSlateBlue, 1.0f, 0);
     
                 effect.CurrentTechnique = effect.Techniques["Colored"];
                 effect.Parameters["xView"].SetValue(viewMatrix);
                 effect.Parameters["xProjection"].SetValue(projectionMatrix);
                 effect.Parameters["xWorld"].SetValue(Matrix.Identity);
                 effect.Begin();
                 foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                 {
                     pass.Begin();
                     device.VertexDeclaration = vertexDeclaration;
                     device.Vertices[0].SetSource(vertexBuffer, 0, MyOwnVertexFormat.SizeInBytes);
                     device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
                     pass.End();
                 }
                 effect.End();
     
                 base.Draw(gameTime);
             }
         }
     }
     


    Google
     
    Webwww.riemers.net


    If you appreciate the amount of time I spend creating and updating
    these pages, feel free to donate -- any amount is welcome !



    - Website design & XNA + DirectX code : Riemer Grootjans -
    ©2003 - 2008 Riemer Grootjans
  • Translations

    This site in English
    This site in Korean
    This site in Czech

    Microsoft MVP Award



    2007 - 2009 MVP Award
    DirectX - XNA

    Contents

    News
    Home
    Forum
    XNA 2.0 Recipes Book (8)
    XNA 3.0 Recipes Book (8)
    Downloads
    Extra Reading (3)
    Matrices: geometrical
    Matrix Mathematics
    Homogenous matrices
    Community Projects (1)
    Tutorials (160)
    XNA 3.0 using C# (89)
    2D Series: Shooters! (22)
    3D Series 1: Terrain (13)
    3D Series 2: Flightsim (14)
    3D Series 3: HLSL (18)
    Starting point
    HLSL introduction
    Vertex format
    Vertex shader
    Pixel shader
    Per-pixel colors
    Textured triangle
    Triangle strip
    World transform
    World normals
    Per-pixel lighting
    Shadow map
    Render to texture
    Projective texturing
    Real shadow
    Shaping the light
    2D screen processing
    Preshaders
    3D Series 4: Adv. terrain (19)
    Short Tuts (3)
    DirectX using C# (54)
    DirectX using C++ (15)
    DirectX using VB (2)
    -- Expand all --


    Thank you!

    Support this site --
    any amount is welcome !

    Stay up-to-date

    I don't have the time to keep a News section, so stay informed about the updates by clicking on this RSS file!