loading...
Cover image for The beginning of my journey: making a rendering engine

The beginning of my journey: making a rendering engine

superfola profile image Alexandre Plateau ・4 min read

Nota Bene: This serie of articles is mainly focused on my experience while making Voksel, a 3D game made in a Minecraft style, so I will only write about my opinion and how I solve the problems I met !

A month ago, I got this strange idea after having taught myself on OpenGL : What if I made my own rendering engine? It could be funny, and I could learn a lot ! That's how I started making Zavtrak. Few days after, another idea hit me: what if I made my own version of Minecraft using this engine ? So that's how my journey started, on a sunny day of September !

I made a small ToDo to know where I was going :

  • abstraction code for :
    • VAO, VBO, EBO
    • shaders
    • free fly camera
    • window creation

(my goal was, and still is, to create a 3D rendering library acting as a nearly 0 cost abstraction for OpenGL)

A VAO acts an array storing vertex (a collection of data per 3D point) attribute pointers, used by OpenGL when given a VBO (vertex buffer object, storing vertices) to know if it looking at a position, a color, a texture coordinate... in a given vertex.

An EBO (element buffer object) is an array storing indexes of vertices (stored in a given VBO) to "link" them :

vertices = [
    # position      # color
    [0.0, 0.0, 0.0, 1.0, 0.5, 0.0],
    [0.0, 1.0, 0.0, 0.0, 0.5, 1.0],
    [1.0, 0.0, 0.0, 0.5, 1.0, 0.5]
]
elements = [
    0, 1, 2
]

defines a right-angle triangle (when giving the data to OpenGL). An EBO avoids repeting the same vertex multiple times, which can be pretty heavy when giving a lot of vertices to the GPU, by only defining the index of the element to use.

A shader is a small program (written in GLSL) to tell OpenGL how to draw a single pixel, given a vertex.

My idea was to have something like this :

auto shader = zk::Shader("shader.vert", "shader.frag");

zk::Vertices vertices({
    // positions         // colors
     0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,   // bottom right
    -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,   // bottom left
     0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f    // top 
});
zk::objects::VertexArray VAO;
zk::objects::VertexBuffer VBO;
// bind the Vertex Array Object first, then bind and set vertex buffer(s)
// and then configure vertex attributes(s).
VAO.bind();
VBO.setData(vertices);
zk::objects::setVertexAttrib(0, 3, 6, 0);
zk::objects::setVertexAttrib(1, 3, 6, 3);

shader.use();
// do drawing...

which is basically the same thing as this (without the window configuration and all, which you can find here), a lot shorter and easier to understand, uh ?

The biggest problem I have now is that we must configure everything ourself (setting vertex attributes, and creating a VAO and a VBO, binding them...) (and I still didn't fix it, since I wanted to focus on the game and rewrite the engine later).

After writing a lot of redundant code, I could start writing a small game with it (you can find my experimentations here). My biggest struggle when I started writing the game was the vertex attributes (as you can see on the cover image, I messed up my vertex attributes and OpenGL handled it as if everything was fine).

GIF: everything is fine

This concludes the first article of this serie, which is more a "explain-me-the-plot" article than a "the-problems-of-writing-a-rendering-engine", but if you want to know my pros and cons of making your own, here they are :

Pros

  • you control everything
  • you can give it the interface you want (I mean, not graphically but programmatically)
  • you understand how it works under the hood

Cons

  • writing your own rendering engine is really hard (I made a very simple one since Zavtrak acts as an abstraction layer for OpenGL)
  • it can take a lot of time (and headaches !)

I will now explain briefly the purpose of this video game I am making, Voksel.

As I said, it is a 3D exploration game made in a Minecraft style, where the player can explore a procedurally generated world made of voxel (3D pixels). The goal behind this project is to create a game in the same spirit as Proteus: an audio-visual exploration game, but with something more: helping the players to relax.


P.S.: I wrote this article in one go, only keeping in mind "how could I introduce you to the problems we met when creating a game", so it can be quite disjointed, I am sorry about that

Posted on by:

superfola profile

Alexandre Plateau

@superfola

A self-taught programmer, video-games lover, sys/net admin on Debian 10

Discussion

pic
Editor guide
 

This is a great awareness article for people like me who think "you know what? I think I can do this without a library / framework".
But when I read "rectangular triangle", I was like wait what? 🀨

 

By "rectangular triangle", I meant a right-angle triangle, sorry if it wasn't very clear --'

Edit: just corrected it, since the "rectangular triangle" is less used (and/or understood) than "right-angle triangle"

 

So that's what it means! I've never heard it before πŸ€”

 

Good writing, Not everyday that i get to read something unique like this ☺️ carry on, looking forward for more.

 

Thank you ! At first, I thought it would have been a bit too messy, that's great if you like it :)

 

This is a great article for graphics enthusiasts who have gotten past the basic triangle and want more out of OpenGL. Thank you so much!

 

Really illuminating. I look forward to more of this, Alexandre.

 

Thank you !

I have already started to write the next article for the upcoming week, with a bit more details (and code !), if it doesn't bother you :D