Ymir Engine: Project Description
Ymir Engine is part of the Game Engines subject, on the third year of the Videogame Design and Development degree, taught at CITM UPC (Terrassa) and supervised by Miquel Suau.
The engine has been made from scratch in C++ using SDL and OpenGL to manage graphics. The main target of the project is to be able to integrate complex systems such as graphics management and game engine architecture in a simple and understandable way for educational purposes.
Team Members: About Us
Francesc Teruel Rodríguez
Game Developer in C++ and C# with high focus on low level systems and engine-related programming.
- GitHub: francesctr4
Joel Romero Botella
Game Designer specialized in the field of characters and levels, with a medium level of knowledge in 3D Modeling.
- GitHub: Joeltecke25
Ymir Engine: Main Core Sub-Systems
The engine is made from several core sub-systems that work together to provide the necessary features to the user, in order to serve as an environment to create games:
Geometry Viewer
Editor
- The engine uses Dear ImGui to provide several windows to customize and manage different aspects of the engine, in order to serve as a controller for the user to take advantage of the features implemented on the engine.
Graphics Pipeline (with Shaders)
-
The engine uses Assimp to import the desired geometry into the engine. The rendering pipeline involves loading the meshes from Assimp and creating the necessary OpenGL buffers to generate the geometry.
-
Moreover, in the case of this engine, shaders are being used alongside the buffers and a Vertex Array Object (VAO) in order to use the programmable pipeline of OpenGL and to be able to do the Shader Pipeline as the last assignment’s High-Level System.
Drag & Drop
- 3D Models with the format .fbx and textures with the format .png or .dds can be dragged directly onto the scene from the file explorer and the engine will load the elements.
GameObject Structure & Components
-
The engine has a GameObject tree structure, where the scene itself is the root of that tree and the several elements on the scene are children of the root node. Each mesh and element is its own gameobject, with components that can be modified.
-
The GameObjects can have children and parents, the same way as Unity manages its gameobjects.
-
Available Components:
- Component Transform: manages the GameObject transformation (translation, rotation, scale).
- Component Mesh: manages the GameObject mesh and geometry.
- Component Material: manages the GameObject appearance (shader and textures).
- Component Camera: creates a camera on the GameObject and serves as a POV (point of view) for the Game Camera.
Hierarchy & Inspector
- Hierarchy: a window that displays the full GameObject tree structure of the current scene.
- Inspector: a window that displays information about the active components of the current selected GameObject on the scene.
Console
- An ImGui window that displays all the engine messages and LOGs so that the user can see and understand what’s going on.
Engine Editor
Camera Frustum
- The camera of the engine has been reworked into a MathGeoLib frustum, that manages all the calculations of the matrices internally. It is really useful to be able to implement the Frustum Culling system, that discards GameObjects outside the Game Camera.
Scene & Game Framebuffers
- The engine has two ImGui windows to separate the game view from scene view, just as Unity does. In order to achieve this functionality, two OpenGL framebuffers have been created, one in each camera, in the respective ImGui window so that we are able to see the two points of view simultaneously.
Custom File Format
-
Ymir Engine has its own custom file format for some of the files that can be opened with it:
- Meshes –> .ymesh
- Models –> .ymodel
- Scenes –> .yscene
- Materials –> .ymat (not implemented yet)
-
They are saved in Library folder using the custom file format.
Serialization
-
Serialization is the process of converting data structures or objects into a format that can be easily stored, transmitted, or reconstructed later. The engine does this in order to save the GameObject stucture of the Scene (including the Components), so that it can be saved and reconstructed when loaded.
-
The GameObjects in the scene are identified using an UID (Unique IDentificator). Some other elements in the engine also use the UID format to be identified, for example, the textures.
Resource Management
-
A resource manager is a subsystem responsible for managing and controlling the usage of various resources required by the application. Resources in this context typically include assets such as textures, meshes, models, and other data needed for rendering graphics and supporting other game features.
-
In the case of Ymir Engine, the Resource Manager it’s the Achilles Heel of the core subsystems, because it’s not completely finished and the resources are still not managed properly. If the project ends up growing in the future, the next step for sure will be fixing the resource manager.
Time Management
- The engine has a Play/Stop/Step system that manages the simulation of the game scene. At the moment the functionality is limited because of the resource manager current state, but all the timers and buttons work correctly.
High-Level System: Shader Pipeline
The last assignment sub-system chosen for Ymir Engine was the Shader Pipeline, which is the sequence of stages that a graphics processing unit (GPU) goes through to render graphics in computer graphics applications. Shaders are small programs written in languages like OpenGL Shading Language (GLSL) that run on the GPU and are used to control various aspects of the rendering process.
- In order to implement the Shader Pipeline in the engine, several features have been developed. They are explained below:
Shader Pipeline for rendering geometry (VAO)
The rendering pipeline of the engine uses shaders alongside a Vertex Array Object (VAO) in order to draw geometry into screen. Here are some screenshots from the code itself that show the insides of the mesh drawing of the engine:
- Bind Buffers
- Draw Geometry while binding the current Shader
Shader Editor
The Shader Editor is an ImGui Window with a Text Editor that is capable of reading GLSL language attached to it. It has an input text field that displays the name of the current shader (modifiable) and several buttons:
-
Create Shader: writes the default shader as base on the shader editor to help you start creating your shader.
-
Save Shader: saves the shader file in “Assets/Shaders/ directory, compiles and loads the shader into the engine. After saving the shader, you can select it from the list of loaded shaders on the Component Material of the GameObjects. In case you were opening an existing shader, it will update the new contents and recompile the shader on the engine.
-
Delete Shader: deletes the current shader opened at the shader editor, from the memory, the list of loaded shaders, the files and lastly from the shader editor itself. No trace of that shader on the engine anymore.
If you want to open an existing shader on your project, you can do it by going to the Assets Window and then opening the Shaders/ folder, and then click on the shader to open it on the Shader Editor.
Shader Hot Reload
- Saving a Shader or changing to another Shader inside the Component Material of a GameObject will recompile the shader on runtime, so that you can see the changes at the moment.
Compilation Messages and Errors
When the process of compilation of a shader is executed, the engine will display some messages on the console, depending on the result of the compilation.
- The first case shows a correct compilation of a Vertex Shader and a Fragment Shader:
- The second case shows an error of compilation in a shader that was trying to be loaded to memory:
Dynamic Uniform Detection
When you load a Shader on the engine, it has an algorythm to detect editable uniforms that you may have created on the shader’s code. Once detected, the engine displays them for you on the inspector and binds them with the shader code, so that you can modify the value from the inspector directly without having to hardcode them.
-
The engine is capable of distinguish between int, float, bool and vectors, and shows you the appropiate ImGui widget to modify the value accordingly.
-
Some Uniforms may appear on the shader code but not in the inspector. That’s because they are essential for the shader functionality and shouldn’t be manipulated by the user. Some examples of this kind of uniforms are: model, view, projection, selected and time.
-
If you delete an existing editable uniform from a shader and then recompile it, the inspector will react as well and will delete that uniform from the list because is no longer there. The same happens if you add a new uniform on the code and save the changes (it will be added to the list of uniforms and will appear on the inspector).
Shader Library
The engine keeps track of the loaded shaders and lets you change between them on the Component Material of the GameObjects.
- If some shader is loaded or deleted, the engine will react accordingly and will modify the list of loaded shaders.
Water Shader
There is a flat mesh (plane) on the scene that simulates simple water. The shader is made from:
- Vertex Shader: creates simple wave movement using sinusoidal functions.
- Fragment Shader: the color of the pixels changes based on its height (dark blue on the bottom, light blue/white on the top).
…and more shaders!
- In order to test the capabily of the engine to actually create the shaders and use them on runtime, some shaders have been created:
Lava Shader
- Water Shader Variant
Rainbow Shader
- Mario Bros Star Effect
Color Shader
- Add color to the material of a GameObject. You can even modify some light settings!
Workflow Video
- Finally, this video shows a speed-up showcase on how to create the demo scene, required for the final delivery of the Game Engines subject, from scratch. Moreover, the video emphasizes the Shader Pipeline and shows the general functionality of all the systems explained above.
Repository and Releases
Repository Link: Ymir Engine
Last Release Link: v0.3 - Shader Pipeline
License
MIT License
Copyright (c) 2023 Francesc Teruel Rodríguez
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.