Blog

Game Engine Progress: Week 1 ยป posted Wed 29 Jan 2020 03:18:33 PM EST

After excitedly spamming a few (very understanding (mostly indifferent)) channels with my progress on writing a 3D game engine from scratch, I decided that this would be a good time to move my blog to a more proper place. So, here's a digest of the progress I've made after about a week of working on the engine, complete with neat videos. The engine is written in C++, using openGL as the graphics backend and SDL2 for input and window management.

Note: There's about 30MB of videos here.

Day 0

Spinning Cuboid

I started out by following the excellent tutorial on wikibooks. This was a good introduction, I would recommend it if you're looking to start programming with OpenGL too. Getting the first triangles on screen was surprisingly satisfying. This first video follows the tutorial pretty closely, with the vertex shader passing a per-vertex color attribute to the fragment shader. It's an interesting visualization of how the fragment shader interpolates between the colors passed from the vertex shader.

Diffuse lighting and textures

Spinning Cuboid++

This video shows some progress after following the tutorials on texturing and diffuse lighting. This already looks pretty neat in my humble opinion, reminds me of old video games. Not coincidence, of course, the simple geometry, per-vertex lighting and (lack of) texture filtering are similar to what could be done in early 3D games.

Here I started to experiment a bit by drawing multiple objects. This was pretty simple actually, at least a naive implementation. The code binds an MVP matrix (model, view, projection) to the shader before calling glDrawElements() to draw vertices by index. So, what if we just update the "M" in there, and repeat glDrawElements() for each object we want to draw? And this works, but it's not terribly efficient as you increase the number of objects. That being said, at the time of writing it runs fine on my netbook from 2009 with an atom n270, so it's probably not worth worrying about just yet.

Multiple lights and fancy camera movement

Spinning Cuboid#

Model loading and specular highlights

Also mipmapping

After dutifully copying the specular highlight shader code, I worked on loading multiple textures and .obj models. It was nice to see some geometry more complicated than the familiar cuboid, as dear as it was. I was surprised at just how simple the .obj file format is, it was pretty painless to get working.

However, contrary to the simplicity of the .obj format, drawing multiple objects with different meshes was more involved than I had expected. While with the cuboids I could just bind a new Model matrix and call it a day, with multiple meshes you need to set up the proper buffer pointers before glDrawElement(). When first approaching this I had thought that this meant simply loading each mesh into it's own VBO (Vertex Buffer Object), and swapping this out per-mesh. However, this would mean I'd have to re-link the shaders every draw call, which is not great (read: absolutely terrible and just horrible in general) for performance. Instead, the recommended way to do this seems to be to have one VBO for each attribute, loading all of the meshes and their attributes into this set of VBOs, and then using a VAO (Vertex Array Object) for each mesh to keep track of what buffer pointers should pointing where. This way you can simply bind the VAO corresponding to the mesh you want to draw and then do a draw call, easy peasy, and pretty quick too.

Materials

Introducing creative commons RPG guy

Now that I could load models into this little world, I felt the irresistable urge to load as many things into it as I could. I ventured out to the interwebs in search of worthy (free) models, and found these neat low-poly models on OpenGameArt . The terrain objects came with material description files, which my little object loader didn't handle yet. They follow the same format as the object files, so adding support for them was straightforward. Now it can handle objects with different material properties without touching the engine code at all.

More testing

Normals ain't normal

Building out a basic test landscape with these new models, and hmm, something isn't right here... The normals don't match where the faces are! This is because the little loader had assumed that there would be duplicated vertices and normals for each face, which isn't the case here. The simple fix is to just duplicate vertices for each face declaration while loading. This increases the number of vertices per model significatly (and so memory usage), but for now this works.

Loading textures and normals

Much better

After the fix mentioned above, and also loading textures from material files, plus texture coordinates and normals from the object files. This looks fairly presentable, maybe a low-poly cartoonish RPG would be a good first game demo...

Map editing, per-pixel lighting

Worst minecraft clone

Most recently, I added a simple map editor and save format, and moved the lighting to the fragment shader. While the cartoonish low-poly look is pretty cool (and I can see why it's so popular among indie games), I want to have more realistic lighting and textures as well, so the per-pixel lighting is in anticipation for working on normal mapping and shadows. It also loads normal and specular maps and passes them to the shader, although the shader doesn't do anything with them just yet. The math for normal mapping is a tiny bit over my head, so it might take a little while to get that working.

Fin.

And so that's all for now, stay tuned for updates, and don't forget to like, subscribe, follow, leave a comment, enable notifications, share, retweet, repost, become a patron, host, raid, cheer, pin, digg, email a link to your parents, and print copies to hand to strangers in the hallway.