About 3D graphics in GMS2. Part 2 of 2

What is a vertex buffer? How to create a 3D object and render it to the screen? What is the vertex format for and how does a vertex shader work with it? How does a depth buffer work and what is depth struggle? How does it affect translucency and why is the order in which objects are rendered to the screen important? How do you calculate camera coordinates and set perspective? What are matrices for and how do you use them? What is clipping and why is it needed?

In the first part I showed how to draw a cube and start rotating it.

If you need to rotate the cube around another point, such as the vertex G, first shift it so that this point is at the origin, and then perform the rotation. To do this, I create a displacement matrix and multiply it by the rotation matrix.

-2

The line marked with a hash is where the Draw event begins. GMEdit shows all the events for an object in one listing and separates them this way. Lines 49-50 show that I enable the depth buffer. Line 4 creates a displacement matrix to position vertex G at the origin. Line 6 multiplies the displacement matrix `ma` with the rotation matrix `mt`.

-3

Now the cube rotates around the vertex G. The order of matrix multiplication matters. For example, I have a translation matrix T and a rotation matrix R . If I multiply them as T x R , the cube will first move and then rotate around the origin. If I multiply them as R x T , the cube will first rotate and then move.

Or another example. Let's say I have a cube matrix M and a matrix R for rotation around the Y axis. If I multiply them as R x M , the cube will rotate around its local Y axis, and if I multiply them as M x R , it will rotate around the global Y axis, as shown in the gif below, where the Y axis is marked with a green line and the X axis is marked with a red line.

-4

Camera rotation and perspective

I stopped the cube rotation and offset. Now it is drawn at the origin again. Next, I will change the camera parameters by moving it in the world and setting a perspective projection instead of an orthographic one. To do this, you need to create the appropriate matrices and apply them to the current camera.

-5

In line 3, I get the current camera. In line 4, I build the look matrix. The matrix_build_lookat function takes nine parameters: the camera position, the camera target position, and the direction of the up axis. Our cube is at the origin, so I set the target to the origin. Line 5 creates the perspective matrix. The matrix_build_projection_perspective_fov function takes four parameters: the field of view, the aspect ratio, the near clip distance, and the far clip distance. By default, GMS2 creates a 1366×768 room, so I set the aspect ratio accordingly. The near and far clip distances set the depth range within which pixels will be displayed on the screen. Lines 7 and 8 set the resulting matrices for the current camera, and line 9 sets these values ​​for the current step, otherwise they will only take effect in the next step.

-6

Now the cube is drawn in perspective.

-7

By clicking the mouse button I will rotate the camera around the cube. To do this I will need to know the radius, latitude and longitude.

-8

In lines 3-5, when the mouse button is pressed, I change the latitude and longitude values ​​using the mouse offset in one step. In lines 7-10, I calculate the camera coordinates, and in line 13, I set them.

Here is the result:

-9

Here I wanted to finish the guide, but decided that I needed to talk in more detail about clipping? translucency and mention the fight for depth.

When 2 surfaces are close to each other, some parts of the back surface may be drawn to the front when rendered to the screen, as seen in the gif below.

-10

This happens because the depth buffer accuracy is not enough to correctly position the pixels in depth, and the further such surfaces are from the camera, the greater the error will be.

To show how clipping works, I'll remove the top edge of the cube.

-11

The bottom and back edges are visible. This is because clipping is currently disabled and so triangles are drawn to the screen regardless of the order of the vertices, clockwise or counterclockwise. Now I enable clipping using the gpu_set_cullmode function.

-12

This gif shows that now the edges that are turned away from the camera are not drawn, thanks to the enabled clipping.

Now I will make one of the planes semi-transparent for the test. The background and the back dark gray plane should be visible through it.

-13

In this gif you can see that the back dark gray plane is not visible through the translucent plane. This happens because the translucent plane is drawn first and the depth buffer is filled with its values, so when I draw the back plane, it is not visible, because the depth buffer is occupied in this place, the drawing stops. Now I will change the drawing order so that the translucent plane is drawn later than the back dark gray one and now in the gif below you can see that the problem has been fixed.

-14

Sometimes game developers use dithering instead of translucency. This allows you not to worry about the order in which objects are drawn to the screen.

So, in this guide I told how to create a vertex buffer and draw it. I looked at working with matrices, rotating a cube with an offset and rotating around different axes. I also discussed how to calculate the position of the camera in space and set the perspective. I explained what a depth buffer is, the fight for depth and translucency. I mentioned clipping and talked a little about GMEdit.

If you liked this article, then:
You can read the first part
Article about shaders

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *