Welcome back. Last time we did a quick introduction to Game Maker 3D using Game Maker Studio 2. Before we can continue to create 3D objects and the rest of the stuffs, we need to discuss about shaders.

(If you missed part 1 of the tutorials, you can read it here)

First of all shaders are a whole topic on their own. So this will be just an overview of how shaders work and what sort of things we may encounter when working with them using GMS2

Default shaders used by GMS2
This is the shader by default used by GMS2

By default, GMS2 creates a shader using a language very similar to GLSL ES. You can follow the official specifications to get a whole overview of the language.

You can also change the language to GLSL and HLSL 11 If you are targeting a specific platform. Because GLSL ES is supported by all platforms and it is also the default selection by GMS, this is the language that we are going to use.

Types of variables

GLSL ES is a strongly-typed language, this means that all the variables must have a type that specifies what kind of data it can handle.

Definition of a variable in GLSL
The order is: type variable = value;

There are several types and modifiers you can apply to it. This is a list of the basic types, but please refer to the official documentation for the full explanation.

To put it in simple words, there are just a few types that you need to think about:

  • Your basic variables from all languages:
    • bool – for conditionals.
    • int – for integer numbers.
    • float – for numbers with a floating-point.
  • Vectors – they can be of different dimensions:
    • 2 dimentional (x,y)
    • 3 dimentional (x,y,z)
    • 4 dimentional (x,y,z,w)
    • They can also have different accesors for when you are dealing with different types of data.
      • The general use accesors are: (x,y,z,w).
      • If you are dealing with colors you can use: (r,g,b,a).
      • If you are dealing with texture data then: (s,t,p,q).
      • so basically x==r==s and y==g==t and so on.
    • They can be of different types depending on the first letter:
      • vec is used for float vectors.
      • ivec is used for integer vectors.
      • bvec is used for boolean vectors.
  • Matrices – The basic usage is to represent things like transformations and projections. They can also have many dimensions.
  • Samplers – Used for texture data. They can also have many dimensions.

To get a full overview of how you can use vectors and matrices you can see a tutorial in lineal algebra. This tutorial from wolfire explains how to use lineal algebra for game development: Link to his blog

Vertex and Fragment Shaders

First, there are 2 types of scripts that we have to work on for every shader.

Vertex Shader

Default Vertex Shader
The default vertex shader created by GMS

The vertex shader has 2 main tasks:

  • Set the position of the geometry to be displayed in the screen. This is achieved by multiplying the geometry data with the object translation and camera projection (we’ll look at this in the next tutorial). The result must be put in gl_Position
  • Pass data to the fragment shader. This data is interpolated between vertices. For example: if one vertex is red and the one next to is green, then it will be interpolate between red and green having yellow in  the middle (which is why our triangle in the last tutorial displays many colors by only having red, green and blue assigned to the vertices).

Fragment Shader

Default Fragment Shader
The default fragment shader created by GMS

The fragment shader has only one task and that is to say which color should a pixel in the screen be, this is done by combining different techniques such as: reading texture data, calculating lightning and shadow information and putting it into the gl_FragColor.

Attributes

Definition of attributes in GLSL
Definition of an attribute.

We can only work with attributes in the vertex shader.

They represent the data from the vertices of the geometry. For example, the vertices position, colors, texture coordinates, joints weights, indices, among others. It can be used in creative ways to send different data to the GPU but those are the usual uses.

The trick is that you can only handle one vertex per operation. So for example, in our example from the previous tutorial we drew a triangle. It had 3 vertices but in the vertex shader we can only handle one vertex and we don’t have any sort of access or information about the other vertices (or even what vertex are we working in).

The reason for this is that the GPU needs to work on as many vertices in parallel as possible to complete the operation.

Attributes In Game Maker

Usually when you work with shaders you can create as many attributes as you want and you can name them however you want. In Game Maker instead we only have a bunch of attributes created and we cannot change their name.

This are the basic ones you can use (You can extend them to have more with a bit of trickery, but for now this would be enough).

GMS2 attributes
Basic attributes in GM Shaders

In order of lines they are for the vertices positions, the normals (for lightning calculations), colors (per vertex) and texture coordinates. We’ll work with them in the next tutorials.

Passing attributes in GMS2

The way we pass the attributes from Game Maker to the GPU is through a vertex format and a primitive. We already saw this in the previous tutorial:

Defining a Vertex Format

Create a vertex format
Defining a vertex format

First we need to define which attributes we are going to use. In the example above we said that we want to use vertex positions (in_Position) by calling the method vertex_format_add_position_3d() and vertex colors (in_Colour) by calling the method vertex_add_color(). We store the result in a variable to work later with it (global.VERTEX_FORMAT).

Defining a Primitive

Create a primitive in GMS2
Creating our triangle primitive

We’ll talk more about building primitives in it’s respective tutorial. But for now, the only thing you need to know is that when you build a primitive you have to follow the same order in which you specified the vertex format. You can see that first I pass a position vertex_position_3d and then I pass a color vertex_color and I always do it in that order.

You can see the constant use of the variable buffer this is the variable that contains the primitive.

Passing the Primitive to the Shader

Submitting a primitive to the shader
Drawing our triangle

To draw our primitive we only need to call the method vertex_submit and pass the variable that contains our primitive.

Uniforms

Defining a uniform in GLSL
Declaration of a uniform in GLSL

The next one to talk about are uniforms. We didn’t see them in our last example, but they are used to pass single data to the GPU. So for example, let’s say you want to color a character depending on how much health he has. If it’s full, then it displays the character with his normal colors, but if it’s almost dead then you may want to display him with a red color. You can pass a color through a uniform that specifies this level of damage.

uniform vec4 u_vHurt;

The uniforms are visible in both shaders, there is no limit on how you want to use them, as it is basically a variable you put a value in. The main usages that we are going to see however are: pass the projection and transformation matrices (We’ll do this in the next tutorial) and pass the image to texture our objects (we’ll do this in a later tutorial).

Passing Uniforms in GMS2

First you need to get the address of the uniform. This is done by a simple call in GML:

Getting a uniform address in GMS2
Obtaining an uniform address

Here we are obtaining the uniform u_vHurt that we defined in the shader shd3D and we are storing it’s address in the variable u_vHurt (It’s a good idea to name this variable the same as it is in your shader).

We only have to do this once, so we usually put this in a script at the beginning of the game (in our case it would be the script scrInitSystem).

Obtaining samplers (The uniforms for the texture) Is done different. But we don’t have to worry about it unless we are working with more than 1 texture.

Sending the Data to the Shader

Now that we have our uniform in a variable we need to send the data. Depending on what type of data we want to send, we’ll have to use a different function:

  • shader_set_uniform_f: This one is used to send floats into a uniform: shader_set_uniform_f(u_vHurt, hurtRed, hurtGreen, hurtBlue, hurtAlpha);
    • There is a variation called shader_set_uniform_f_array which is used to send an array of floats instead of the values themselves: shader_set_uniform_f_array(u_vHurt, hurtColor);
  • shader_set_uniform_i: The same behavior than the previous one but you can only send integer values with this. (You can also use the shader_set_uniform_i_array variation to send a array of values).
  • shader_set_uniform_matrix_array: This one is used to send a matrix through a array: shader_set_uniform_matrix_array(u_mProjection, projectionArray); It also has a version without the _array part but it has a different behavior left for the constants of GMS2, we are not going to use that version though.

Varyings

The last thing we need to talk about are the varyings.

Defining a varying in GLSL
Definition of a varying

They are defined in the shaders themselves so you don’t pass data directly to it.

They need to be included in both the vertex and fragment shaders. And must be called exactly the same with the same type as well.

They are used to interpolate values between vertices (usually passed through an attribute). Reviewing our example of the triangle again. We have 3 vertices, and each vertex has a color and a position assigned to it. We used a varying to interpolate the colors. That’s why it changes from one vertex being red, going slowly to yellow and finally getting green in the next vertex

Displaying a triangle with color interpolation
In the middle it gets gray because all the colors (RGB) are the same value there

Passing a Varying from the Vertex to the Fragment shader

Using varyings in GLSL
We are interpolating the colors in this example

First you can see we defined the varying vec4 v_Colour; Then inside the main method. In line 11, we are defining which value is this vertex going to have (one is red, the other is green, the final one is blue) by assigning the varying (v_Colour) with the value obtained from the attribute (in_Colour).

Receiving the Varying in the Fragment Shader

Reciving varyings in a fragment shader
Receiving the varying

In the first line you can see the same definition of the varying vec4 v_Colour; Same type, same name.

In this step the variable is already interpolated. We may have a red value, a yellow, a green or a gray.

The final step is in line 5 where we output that color to the screen (gl_FragColor).

Wrapping up

There is still a lot to be written about shaders. As I said at the beginning they are a full topic on their own. But with this little info we can start sending data to the GPU and have all sort of interesting effects going on.

This is going to be all for this tutorial. In the next one we are going to talk about the projection and transformation matrix.

Thanks for stopping by.

I always wanted to talk about 3D development using game maker but I never really found a format that I liked. I made some small courses in spanish over Youtube but I never was quite happy with how it was scalling, so this is a new attempt to bring this topic to the people.

Now, I know, why would you even attempt to create 3D games with Game Maker when tools like Unity, Unreal and Godot are much better for this task and have very good license deals?

Well, I don’t really have an answer to that, those engines are obviously much better than Game Maker will ever be for 3D. with that being said, there is still knowledge to be gained with this experiment.

While Unity and the others are really powerful, they remove a big chuck of the pipeline involved in the 3D rendering. This is great for businesses obviously, since you want to use the shortest path possibble to release your product, but if you want to improve your skills as a programmer then you should really tackle this and many other difficult tasks.

This mini course is just going to talk about how to set up a 3D dev environment using Game Maker Studio 2, any tutorial beyond that will be made in a general OpenGL/WebGL engine.

You don’t need any previous experience doing 3D, but you should be confortable using the Game Maker Engine before continuing.

CREATING OUR FIRST TRIANGLE IN GAME MAKER

It may sound like a simple task, but this is the most important step. It happens more often than not that when you set up your 3D environment you don’t get to see anything you drew to the screen. Debugging an OpenGL application can be a real pain. That’s why it’s important to make sure you can draw things.

You can find a Github repo for this course in at the end of this post.

Let’s start by creating our assets in the project. Open Game Maker Studio 2, create a new project and add this files:

  • A script called scrInitSystem, this one will be used to initialize all the global variables needed for this project.
  • A shader called shd3D, Since Game Maker uses a 2D shader by default, we will create our own shader.
  • An object called objSystem, this is the main object for the game, it’s going to handle all the 3D functions.
  • An object called objTriangle, This is our object to be displayed.
  • room should be added by default by the engine.

By now, your hierarchy should look like this:

The hierarchy of the project showing all the assets created so far.
This is how your project should look so far

Shd3D

Let’s start by modifying our shader. Now, if you don’t know how to use shaders, they are a whole topic on their own. We will discuss them on time but for now I just want you to copy what I’m going to show you.

This is how a shader looks by default when you create a new one:

Default shader created by Game Maker
Vertex Shader of a new Shader

What we are going to do is to eliminate all of the unnecesary data and leave only the attributes needed to place our triangle, and then add color to it.

Make sure you are on the first tab shd3D.vsh this is the vertex shader, and paste this code.

Custom Vertex shader that receives a color and a position
Vertex shader

Then, go to the second tab shd3D.fsh which is the fragment shader, and add this.

Custom Fragment shader that draws a color to the screen
Fragment shader

As I said, don’t worry too much about what we just added, because we will talk about shaders in detail in another post. Basically what this shader does is: It receives 2 types of parameters: a position, and a color. Then, it interpolates between the colors from vertex (position) to vertex. Finally it draws it to the screen.

scrInitSystem

Let’s continue with this script, the objective is to initialize all the global variables that we are going to need, this script should be executed at the beginning of the game by the objSystem. This is how it should look:

Initialize the vertex format to be used in the 3D application.
scrInitSytem

Since we added a custom shader that receives a position and a color, we need to make sure that we are going to send that same data. So what this script does is to create a new format (vertex format) and then we tell it that we are going to first send a position (vertex_format_add_position_3d) and then a color (vertex_format_add_color). This order is extremely important because later when adding our primitives (the triangle in this case) we need to create it using the same order.

objSystem

This is the object that will control how things are going to be draw in the future. For now it is a really simple object.

Add the create event for this object and add this lines:

Event Create for the objSystem
Event Create for the objSystem

The first line calls the scrInitSystem script and the second line creates the objTriangle. Nothing more.

objTriangle

Finally, the star of this tutorial. The objTriangle Is going to create the primitive and then it will send it to the shader where it will be draw.

Add the create event and add the next content:

Event Create for the objTriangle
Event Create for the objTriangle

Lines 2 and 3 are used to tell Game Maker that we are going to build a primitive. Note the use of global.VERTEX_FORMAT this is the format we created in the script scrInitSystem. Remember that it has an order that we need to respect.

The lines 6-7, 10-11 and 14-15 are used to create the geometry of the triangle, we will talk more about this in another post, but you can see that we kept the same order always: first position_3d, then color

The last line is to indicate that we are done building our object.

Now, let’s move onto the draw event

Draw Event for the objTriangle
Draw event for the objTriangle

First, in line 2: we are setting our custom shader to be used.

After that in line 4: we are submitting our geometry (created in the create event of the objTriangle) to the shader, (don’t worry about the pr_trianglelist and the -1, we’ll talk about that in the primitives tutorial).

Finally we reset the shader to use the default of Game Maker, this is so to avoid any conflicts with other things being draw.

Adding things to the Room

The last thing left to do is to add the instances to the room. You only need to add the objSystem since that object is the one that creates the triangle after the global variables are initialiazed.

Objects added to the room
Note that the only object added is the objSystem

And that’s it! if everything was added correctly, this is how your game should look when you run it:

The result of this tutorial
So  awesome!

It may not look like much, but as I said, this is the most important step. The next tutorials will talk more in focus about specific topics: Matrices, Shaders, Cameras, Primitives, etc.

Congrats if you made it this far! If something maybe didn’t work then you can ask me in the comments section or you can download the source code for this and the other tutorials:

https://github.com/jucarave/tutorial3DGMS2

Continue now to part 2

Thanks for stopping by and have a nice day!

It’s been a while since I posted anything to this blog. Here I am trying to revive it again.

This time, I do have some good news, Last month I participated in the July VIP Teach Challenge Hosted over skillshare. skillshare it’s a great platform for everyone to talk about any little skill that they may have. Some people take it to the extreme and do really professional courses over there.

I’ve been doing videotutorials for game development using Game Maker for over seven years now, mostly over youtube and in spanish. This experience of doing a course over a topic that is not my main strength and also in another language really proved to be quite the challenge.

My first course over Skillshare

I chose to teach about pixelart this time. I haven’t been doing it as much as game programming but I’ve been improving quite a bit in the last year, so I felt like I should share some of my experience.

All the styles and used for the course

The whole course is developed using aseprite and a graphics display tablet (although a mouse is also a valid tool). The main idea is to draw an original character using 5 different styles: 4 from other videogames, I chose: Sonic, Metal Slug, Pokemon and Blasphemous. The final one is a drawing using our own style applying what we have learned over the rest of the course.

After this, we draw them again in different poses. I chose a site called quickposes to select some interesting pictures from people to use as a reference.

Drawing my original character in the metal slug style 

I will continue to release new courses, mainly in pixelart but I’m pretty sure that I will switch to teach game programming at some point as well.

If you are interested in learning how to do pixelart, you can check my course over skillshare and also get a 2 month free trial for this or any other course over the platform using this referal code.

https://skl.sh/2vmeyji

Thanks for stopping and I’ll see you next time.