How was the snowman made?
During year 2022, I've had an idea in my head for quite some time to go back to the erLett project and restart it. Alongside working on Repeat, I was building very small test applications where I was working with the Vulkan API. These were very basic things like rendering a triangle or later a working replica of Asteroids. Over time, these tests put me in a position where I was holding myself back from restarting the project with the idea of implementing it outside of an existing engine, and rather focusing on the content part instead. But the idea increasingly teased me: after all, it couldn't be that difficult to integrate an external physics engine into a simple rendering system that was already working for me. Similar thoughts haunted me until November.
In November I decided that I didn't want to restart erLett, but to try something that was more realistic to finish by winter, ideally around Christmas. This timeframe was a key step towards completing the project. The theme was a greeting card or a New Year's wish. The scope was clear:
- iteration of the graphics from the project v-obrazoch
- first-person camera
- the goal of the game is to build a snowman
- you can add different objects to the snowman
- some objects can be accessed using snowballs (this didn't make it into the game)
- the whole game is implemented in Odin, it uses the Vulkan API directly, without any graphics or game engine
After that, about a month of work on the editor began. Personally, I think this step was not that necessary but it did make some parts easier in the end. In fact, it would have been more than realistic to just create the game in the blender and then import the entire scene to represent the game world. The main reason I decided to go with a custom editor was the specific visuals. The editor showed the scene in the final visuals. Over time, the editor was also useful when working with colliders.
Parts of the code were ported from the project v-obrazoch. A good example is the camera controls. The graphical interface of the editor uses a very used library in game-dev: ImGUI. However, this time the project was created in Odin. In contrast, the project v-obrazoch was written in c++. So the development was accompanied by both translating c++ to Odin and creating binding code for some libraries like the aforementioned ImGUI. I created a custom generator for ImGUI. I describe the details of why I chose to do so in its github readme: https://github.com/foxik0169/imgui-odin. ImGUI was only used for the editor and is not available in the released game.
I have been following the Odin language for a long time. In short, it is a simple procedural language that aims to provide a more modern alternative to C. Thus, it does not work with OOP. It also has no automatic memory management. One has to work with different allocators and manage memory manually. This doesn't affect the snowman that much, as the game is really small. Unlike C, it has basic data structures like hashmap, dynamic array and slice (basically a structure containing a pointer and a length, but the language has a specific syntax that makes it easier to work with these types).
I used the Bullet Physics 3 library for the physical simulation. Working with the library was a bigger ordeal than e.g. ImGUI because there is no C api for Bullet to write binding code on. Of course there is a way to bind c++ code to other languages, but I found this route unrealistic within my time constraints. Therefore, I decided to create a c++ library that published a C api for calling from my Odin program.
As for other libraries, I initially thought of using FMOD for sound. However, after manually creating the binding code :), I decided to replace the library with the opensource alternative OpenAL-soft. Sure, the libraries have completely different levels of features and complexity but for such a simple project I thought it was nice to use this option and thanks to that not have to display the company logo on the intro screen. In the end, there was no music anyway and the game was left with just the sounds.
The principle of the visuals was created just for the v-obrazoch project while I was still a student and with the financial support of the faculty. The vertices of objects are shifted in real time (in the shader) to the nearest precomputed random point within the screen.
Since the visuals produced by this process were too intense in the first-person camera, I added a simple weighting to the implementation based on the vertex distance from the camera. That is, the effect is applied with less intensity to distant objects than to close ones. This intervention was also recommended by indie game developer community, where I shared demos of the actual state I had under my hands.
At the same time, simple cel-shading - two-level shading - is added in the current version. I added it because without any shading the objects were just an animating silhouette and thus relatively difficult to navigate.
Footsteps and snowball tracks
The player footprints and snowballs also add quite a bit to the game's character. The player footprints are implemented by instanced geometry: only a model of one footprint is sent to the GPU, and the transformation matrix of each step. Snowball traces are created entirely on the CPU as a separate model, for each snowball separately.
I think this project was a success. Porting OpenGL code to Vulkan, learning the Vulkan API and wrapping it all up with a project that has a beginning and an end was a good decision. There are definitely easier ways for example using an rendering abstraction library or a simpler API like DX11 or just OpenGL. It was a good learning experience and if there is someone who is interested in low-level code, I would definitely recommend trying to create a project that has an ending.
The Vulkan API is very verbose and manual, which may cause resistance at first impression. In some cases, however, it is better to work with, because of the validation layers available in the Vulkan SDK. It also doesn't incorporate many concepts from hardware that is now obsolete. On the other hand, as Vulkan is targeting a large variety of devices (mobile - console - pc), there is a chance that the code you write won't work on some of them.