MINECRAFT-How does it work? (part 2)
gagecantrelle
Posted on July 20, 2024
Hello. If you haven't read part 1, I recommend you read that before you read this. To recap on what I talked about, it's about what the code of Minecraft looks like. Some of you might want to build a similar game to it or just want to try and change yourself. Whatever the reason, you are curious about it since this is a popular game we are talking about. So let's continue. I left off in part 1 of MINECRAFT-how does it work, also here is the link for part 1 https://dev.to/gagecantrelle/minecraft-how-does-it-work-part-1-1i8l.
Before starting let's refresh our knowledge of Minecraft
- made by a Swedish game programmer Markus Notch
- made in 2009
- sold to Microsoft in 2014
- Became popular after being sold
Buffers, what are they and why would we need them? If you remember, part 1 talked about Vertx data and the process, you need something to pass it to OpenGL. A Buffer is basically like a storage unit on the GPU, it can hold any data type.
In OpenGL, there are different buffer types for different tasks. Here are some common buffers that are used GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_TEXTURE_BUFFER, GL_DRAW_INDIRECT_BUFFER, GL_SHADER_STORAGE_BUFFER, GL_TRANSFORM_FEEDBACK_BUFFER, and GL_UNIFORM_BUFFER.
Let's talk about GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER first. So how do we use the two buffers? First, we need to create an array buffer
with the glCreateBuffers function. Passing it a number and ID so we can target it later. Next, we need to tell it what type of buffer it is supposed to be with glNindBuffer(). The parameters that it will take are the buffer type and the buffer ID you created. Finally, we need to use the glBufferData function to pass in our data. It will take in four parameters: the buffer type, the size of the data, the data itself, and usage. The last parameter is used for telling what we intend to do with the data. Here is some links to the Doc that talk about all the usage types. https://registry.khronos.org/OpenGL-Refpages/gl4/html/glBindBuffer.xhtml
https://registry.khronos.org/OpenGL-Refpages/gl4/html/glBufferData.xhtml
After creating the buffer and giving it data to use, how can we use that data? By using a Vertex and Fragment shader. Now let's say we want to send
the position and color data. First, we need to use the layout function to set the position where the Vertex data is at.
Now we need to use the glVertexAttribPointer function, to tell the GPU that the buffer holds vertex data.
It will take in six values GLuint, GLint, GLenum, GLboolean, GLsize, and offsetPointer
- GLuint - index/location data for where it at
- GLint - size / how many components this attribute has - Must be a size of 1, 2, 3, or 4 for basic data type - For a vertex 3 data type you use size 3
- GLenum - type / the type of data - If you use vertex 3 you use GL_FLOAT
- GLboolean - normalized / if you want data pass-in to be normalized - Integrate to float data type - Normalized: has many meanings depending on its use, but to put in a general term for code. It's the Process of organizing data in a database to eliminate redundancy and inconsistencies - Depending on how you look it up on Google you will get different types of Normalized. like the version to get Unicode in javascript - Good for converting color data to normalized range data
- GLsize - stride / determine how many bites each vertex is - if the data is tightly pact meaning there is no gap between vertices, then set the value to 0 to represent the tightly pact data
- const void* offsetPointer - ask for the offset of the data
After you call that with the correct values, you need to run the function glEnableVertexAttribArry. This takes in the number that represents the layout location in the shader. That makes sure that OpenGL enables this vertex attribute as part of the state for the vertex array
We know how to create a buffer and make data pass to the buffer, but how do we combine them with OpenGL? By using Vertex Array Objects Better known as VAOs. But what is it VAOs? Well, it's similar to an OpenGL buffer with its unique IDs, with only one difference, that instead of storing data, it stores how our data should work.
Next we create bind and create a vertex array by using the glCreateVertexArrays and glBindVertexArray functions. The reason why we have to bind it after creating it is because OpenGL is like a big state machine.
Then, let's say you don't want it to be bound anymore, rerun the same function again but pass in a 0. Now let's take a five-minute break to take a good look at an example to see how this would look.
Ok, now that we just need to run it through the shader. Unfortunately, we won't talk about shaders due to them being at a point where they should be in their own blog. I explain more about them in part 3 of Minecraft-how does it work? Move on from that when we get the shader working we need OpenGL to draw the data from VAO. To do this we need to use two functions glUseProgram with the shader as a parameter, and glDrawArrays. The parameters for that are the Primitive first, then the start index, and finally vertex count as the last. Let's say we have twenty vertices, the starting point is fourteen and the court at six. The data will be drawn from vertices fourteen through nineteen.
Now that we have all the functions and data set up, we can draw something. But wait, we have a problem that we need to fix first before moving on. The problem is the duplication of vertices when something is drawn since some vertices share the same data. Let's say we draw a star with ten vertices but we want to use 8 triangles, then we would need twenty-four Vertices.
How would we fix this? Luckily OpenGl thought of a way to fix this with the Element array buffer/GL_ELEMENT_ARRAY_BUFFER. This buffer will tell OpenGL that we want to reuse some of the vertices.
The way to set up the element array buffer is pretty much the same as setting up the array buffer.
Now how do we set the elements? The doc states that it can only be assigned one of three values: unsigned bytes, unsigned shorts, and unsigned ints. The OpenGl doc doesn't explain where to declare the data type we're using. We can specify it when drawing the elements, then declare them as unsigned ints with unit32_t. When the data is uploaded with the functions in the last images with the buffer being created. While the VAO is bound, that buffer will be related to that VAO.
While the VAO is bound to the buffer we can use a different OpenGL function to draw it. The VAO must also have an element buffer bound for this to work. The function we will use is called glDrawElements it takes in the Primitives, a number that will represent how many elements and how many to draw. Next, we need to assign them with a GL_UNSIGN_INT. Finally, we pass in an offset, if we set the offset to three it will start at the third index in the array. In the doc, it refers to this as a pointer because you can pass the element buffer directly to OpenGL here. Though you shouldn't do that because you need to upload the data every time the function is called. So instead think of this as an offset in the element array where you start drawing from.
This is a lot to take in from buffers to elements, vertices, etc. But it is important for creating an engine for a game to run on even if it is a Minecraft copy or not. Though we did skip talking about shaders we will talk more about them in part 3. Also, all information used in the creation of this blog is in the part 1 blog. Like I said in Part 1 this will not teach you how to make Minecraft but show you the steps that you might need to do if you're making a Minecraft copy or something similar.
Posted on July 20, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 27, 2024