Vertex Formats


In general when you start working with 3D, special effects, complex drawing processes or shaders you don't need not worry too much about the vertex format being used, since GameMaker Studio 2 will automatically set up and pass through the vertex data for you. However, sometimes it is necessary to create your own vertex data and format it to suit, especially when you need to boost speed, or wish to pass in extra information. For example the standard vertex format includes an x, y, z 3D position, colour (with alpha), and UV texture coordinates, which, if you were creating it yourself, would look something like:

vertex_format_begin();
vertex_format_add_position_3d();
vertex_format_add_colour();
vertex_format_add_textcoord();
my_format = vertex_format_end();

However, if you are only using (for example) the shader to manipulate the position of the vertex, then there would be no need to pass through colour or texture data. In this case you would create your own format as so:

vertex_format_begin();
vertex_format_add_position_3d();
my_format = vertex_format_end();

You should note that once you have created your vertex format, the order in which you have defined the vertex properties must be honoured when building your primitives. So, if you have defined a vertex format as position, colour, texture coordinate, then you must add these properties to the primitive in the same order otherwise you will get an error. Also note that like any other dynamic resource, a vertex format requires memory and therefore should be removed when not needed using the function vertex_format_delete().

The section below deals with how the defined vertex formats are mapped within the shader to the correct attributes:

As we have already mentioned above, vertex formats are built up by using together the following 5 attribute types (added via the appropriate vertex_format_add_* function):

  • Colour
  • Normal
  • Position
  • 3D Position
  • Texture coordinate

Within the GLSL ES shader, these kinds are recognised using the following 4 attributes:

  • Colour
  • Normal
  • Position
  • Texture coordinate

Now, this might look odd as it seems that we can specify more attribute kinds in our vertex format than we can in the vertex shader. However, in the shader Position and 3D Position are treated as the same attribute, except that Position is expected to have only "x" and "y" coordinates whereas 3D Position has “x”, “y” and “z” coordinates. So how do you map what's in your vertex format to how you define attributes in your shader? Let's start by looking at a typical set of attributes from the default shader:

attribute vec3 in_Position;        // (x,y,z)
//attribute vec3 in_Normal;        // (x,y,z) unused in this shader.
attribute vec4 in_Colour;          // (r,g,b,a)
attribute vec2 in_TextureCoord;    // (u,v)

And here's a chunk of code which sets up a vertex format compatible with this shader:

vertex_format_begin();
vertex_format_add_position_3d();
vertex_format_add_colour();
vertex_format_add_textcoord();
my_format = vertex_format_end();

Now, how does the shader attribute get matched to the vertex format kind? It's just based on naming convention:

  • "in_Position" maps to vertex_format_add_position / _3d()
  • "in_Colour" maps to vertex_format_add_colour()
  • "in_TextureCoord" maps to vertex_format_add_textcoord()

Now, things get trickier when you have multiple attributes of the same kind, but things are still based on the same naming convention. We'll look at supplying additional colour and texture coordinates now, as there can only be one Position and one Normal attribute in the shader or vertex format.

When adding additional colour attributes to your shader, a number needs to be added to the end of the shader attribute to indicate which particular entry in the vertex format the attribute maps to. Here's an example - first the vertex format:

vertex_format_begin();
vertex_format_add_position_3d();
vertex_format_add_colour();
vertex_format_add_colour();
vertex_format_add_textcoord();
my_format = vertex_format_end();

And now the associated shader attributes:

attribute vec3 in_Position;      // (x,y,z)
attribute vec4 in_Colour0;       // (r,g,b,a)
attribute vec4 in_Colour1;       // (r,g,b,a)
attribute vec2 in_TextureCoord;  // (u,v)

In this case in_Colour0 maps to the first vertex_format_add_colour() and in_Colour1 maps to the second.

Texture coordinates are handled slightly differently to colour. Basically, anything which isn't called in_Position, in_Normal or one of the in_Colour[0 ... ] attributes is treated as a texture coordinate. The order they are defined in, in the list of attributes in the shader, is what denotes which attribute in the vertex format they map to. See the following GML example:

vertex_format_begin();
vertex_format_add_position_3d();
vertex_format_add_colour();
vertex_format_add_textcoord();
vertex_format_add_textcoord();
vertex_format_add_textcoord();
my_format = vertex_format_end();

And the shader code would look something like this:

attribute vec3 in_Position;      // (x,y,z)
attribute vec4 in_Colour;        // (r,g,b,a)
attribute vec2 in_myTexcoord;    // (u,v)
attribute vec2 in_TextureCoord;  // (u,v)
attribute vec2 in_Something;     // (u,v)

In this example, in_myTexcoord, in_TextureCoord and in_Something map to the three successive texture coordinate attributes defined in the vertex format.

The following functions are available for defining vertex formats:

One final important point to note when using your own vertex buffers in this way is how it affects the vertex batches that are sent to the GPU. When you create a vertex buffer you are creating the lowest level of graphics data, so when you draw all that happens is we send your buffer directly to the graphics card. Because of this, if you want better batching, you must work it out yourself and store things you want batch inside the same buffer. So you can't put in 3 sprites then draw many of them and expect vertex buffers to be merged - you're in charge of vertex buffer data at this point. If you want auto-batching then you have to give the engine higher level primitives - like a sprite - at which point GameMaker Studio 2 can work out what your doing, and fill buffers properly.

Building Primitives

Once you have defined your new vertex format, you can then go ahead and build your primitives that will use it. The functions available for this can be found in the following section:

  1. Building Primitives