Hey! In this tutorial, you’ll learn how you can use vertex buffers to draw static sprites. If you have a lot of static sprites to draw, using vertex buffers can be a lot faster than using objects or draw_sprite() functions. The grass in my grass asset is drawn using vertex buffers.
The grass is static even though it appears to be moving. That is done using shaders.
So, let me show you how you can draw a simple sprite using a vertex buffer.
A vertex format specifies what kind of data will go into a vertex buffer.
For drawing a sprite, we mainly need three data types: 2D position (position of the sprite inside the room), Texcoord (position of the sprite on the texture page) and color.
So here’s how I’ll create the vertex format (all of the code hereafter is in the Create event):
vertex_format_begin(); vertex_format_add_position(); vertex_format_add_texcoord(); vertex_format_add_color(); var format = vertex_format_end();
vertex_format_begin() will start creating a vertex format, after which we can add the data types we want. So here I’ll add “position”, “texcoord” and “color”. Then vertex_format_end() ends the process of creating the vertex format, and returns its ID so that it can be stored in a variable.
Now we can make the vertex buffer.
vbuff = vertex_create_buffer();
This will create a vertex buffer and store its ID in vbuff.
Drawing the Sprite
Note: Open Tools > Texture Groups and make sure “Automatically Crop” is disabled.
A vertex buffer takes points. By adding points, we can build triangles. For drawing a sprite, we have to create two triangles that will make a rectangle to draw the complete sprite:
Since one triangle has three points, in total we’ll need to add six. But before that, we must create some variables:
//sprite tex = sprite_get_texture(spr_test, 0); var uvs = texture_get_uvs(tex); var uv_left = uvs; var uv_top = uvs; var uv_right = uvs; var uv_bottom = uvs; var left = x; var top = y; var right = x + sprite_get_width(spr_test); var bottom = y + sprite_get_height(spr_test);
The function sprite_get_texture() takes a sprite and image index and returns its texture. That texture will be stored inside tex.
The function texture_get_uvs() returns the UV coordinates of a texture, inside an array. Basically, those UV coordinates are the top, left, right and bottom coordinates of the texture on the texture page. So, accordingly, those values will be stored inside variables uv_left, uv_top, uv_right and uv_bottom.
Next, the variables left, top, right and bottom will store the coordinates inside the room where the sprite is to be drawn.
Building the Triangles
Now, it’s time to build the triangles:
//begin vertex_begin(vbuff, format); //triangle 1 vertex_position(vbuff, left, top); vertex_texcoord(vbuff, uv_left, uv_top); vertex_color(vbuff, c_white, 1); vertex_position(vbuff, right, top); vertex_texcoord(vbuff, uv_right, uv_top); vertex_color(vbuff, c_white, 1); vertex_position(vbuff, left, bottom); vertex_texcoord(vbuff, uv_left, uv_bottom); vertex_color(vbuff, c_white, 1); //triangle 2 vertex_position(vbuff, right, top); vertex_texcoord(vbuff, uv_right, uv_top); vertex_color(vbuff, c_white, 1); vertex_position(vbuff, right, bottom); vertex_texcoord(vbuff, uv_right, uv_bottom); vertex_color(vbuff, c_white, 1); vertex_position(vbuff, left, bottom); vertex_texcoord(vbuff, uv_left, uv_bottom); vertex_color(vbuff, c_white, 1);
vertex_begin() starts the vertex building. After this function, you can start adding the points.
The points must have data for each type created in the vertex format. Since our format had position, texcoord and color, you can see that each of the 6 points have those values.
This way, I am creating those two triangles. The first triangle has three points: (left, top), (right, top) and (left, bottom):
And the second triangles has these points: (right, top), (right, bottom) and (left, bottom):
The color is simply c_white with 1 alpha.
At the end, I’ll add this:
Finally, I’ll add this to the Draw event:
vertex_submit(vbuff, pr_trianglelist, tex);
This submits the vertex buffer so that it can be drawn. The first argument is the vertex buffer itself, the second argument is the primitive type, and the third argument is the texture to be used.
You can add depth to the vertex points. Before creating the buffer, you have to use this function:
This function will enable depth testing.
Then, in the vertex format building, instead of vertex_format_add_position(), you should use vertex_format_add_position_3d():
vertex_format_begin(); vertex_format_add_position_3d(); vertex_format_add_texcoord(); vertex_format_add_color(); var format = vertex_format_end();
Then when you’re building the vertex triangles, you need to use vertex_position_3d() and in the last argument, add the depth.
//triangle 1, point 1 vertex_position_3d(vbuff, left, top, 100); //100 depth vertex_texcoord(vbuff, uv_left, uv_top); vertex_color(vbuff, c_white, 1);
This should apply depth to the vertex buffer.
When drawing the sprites, there might be a problem where you can’t see a sprite behind one. In other words, the empty parts of a sprite might not appear empty. To fix that, use this before the vertex_submit() function in the Draw event:
That’s it! There’s a lot you can do with vertex buffers, and when used with shaders, you can make some amazing effects, like my grass asset:
If you want to support me, you can do so by checking out my assets. (^_^)
See you later, and till then, happy dev’ing!