Introduction
The Ares Engine can morph into practically any kind of game engine one might desire. The engine architecture is based upon plugins to make modifying and extending the game engine a very straight forward effort. For example, even the game loop, while perhaps the core concept of any game engine, is itself a plugin, making it possible to replace one game loop for another by merely swapping one plugin for another.
The engine core is limited to just the bare essentials to load the plugins and integrate them into a cohesive system that can work together. (It is, in a sense, just a boot strap loader and API layer.)
The code is designed to for clarity. For example, the entry point of the engine defined by the Windows operating system is the C function, WinMain. This can be found in the windows' executable project in a file MainEntryWin32.cpp, whose name is designed to facilitate easy discovery for the entry point.
There is a plugin manager that is solely responsible for loading plugin modules at runtime and is operating system specific (e.g., dynamic linked libraries for Windows, shared objects for Linux, etc.).
There is an operating system agnostic platform which is well known throughout the code base that acts as an API layer to which each plugin can publish their interfaces, and through which each plugin can access the API of other plugins.
Interfaces
The code base uses abstract C++ classes to define interfaces. Each plugin publishes one or more interfaces for use by other plugins. These interfaces represent what services the plugins offer each other and to the game engine itself.
Plugin
Plugins are installed into the engine through the following steps:
Discovery - The first thing the engine does is discover all of the plugins that are installed.
Loaded - Each plugin is loaded and instructed to integrate with the engine.
Initialize - All plugins are initialized, gathering the interfaces to other plugins and preparing to provide their services to other plugins.
startup - All plugins begin normal operations.
The Game Loop
Once all plugins are ready to be fully used, the main code passes control to the GameLoop plugin.
The game loop is simply a sequence of event signals being raised, one after another. They are synchronous in nature. One signal must have fully processed across all plugins that subscribed to it before the next event signal is raised. It is through this signal architecture that the code supports a robust design of separation of responsibilities, preventing one part of the engine knowing the implementation of another, and thus reducing the maintenance burden when making changes to any one part of the engine code.
In addition, though the sequence of signals being raised throughout the game loop is synchronous, this doesn't prevent the plugins from responding by initiating asynchronous tasks. However, the burden for managing the thread synchronization falls on the code responsible for initiating the tasks.
The game loop must play nice with the operating system. The game loop looks for operating system events near the top of the loop and queues as many as possible for processing later in the loop rather than blocking.
Tokens & The World Manager
The scene is managed by the world manager, a plugin that bookkeeps the Tokens in the World. Tokens are the objects in the scene, both those that you can see because they render, and those that are never visible (audio, rules, data, etc.).
The world manager includes a streaming service that helps game developers stream in sections of their open worlds in intelligent and optimal fashion.
The Player possesses a Token to interact with the scene. Once a Player has possessed a Token (a Pawn, usually a character Token), it can then have its possessed Pawn possess another Token (e.g. vehicular Token). The entire design is to simplify the game developer's effort to interact with and take control of vehicles or other types of Tokens.
Rendering with Vulkan
The rendering plugin that comes default with the engine utilizes the Vulkan API to render with modern GPUs. The plugin is designed to make use of multiple discrete GPUs (dual GPU cards in a single box) to support multiple local players (e.g., coop campaign or multiplayer).
Memory is allocated by the plugin in heaps. (Images are stored in GPU memory apart from these heaps.) The direct heap is the GPU memory that is directly accessible by both CPU and GPU. The indirect heap is that memory only accessible by the GPU. The shared heap is the CPU memory accessible by both CPU and GPU memory. Each has their uses based upon their performance characteristics.
To support large worlds, the scene is broken into concentric spheres - rings. Each ring represents a range of distance from the camera. Meshes are rendered in order from nearest ring to furthest ring for opaque meshes, and then furthest to nearest for translucent meshes. The first ring is 8m; the second is twice that, 16m; the third is twice that, 32m; and it continues for as many rings as the game is configured for. 6 rings should be adequate for a 2km x 2km scene. This ring design intends to balance fragment shader processing of occluded meshes against the computational effort of ordering each mesh individually.
Mesh level of detail (LOD) is auto generated upon asset import.
3D animation is accomplished with up to four weighted joints.
A compute shader is ran at the start of each frame rendering to calculate which meshes are to be rendered, at which level of detail and from which ring. Then a series of indirect draw commands are performed for each ring twice - once for opaque meshes, and once for translucent meshes.
This is done twice - once for terrain meshes and once for non terrain meshes. The difference is strictly in the shaders being called by the graphics pipeline.
The plugin utilizes the Physically Based Render Diffuse Model. Not all of the PBR DM is utilized, but for optimization purposes, some elements are multiplexed. For a first person shooter with the art style targets being sought, this balance is intentional. (For example, a mesh can only represent or contain ambient occlusion, mask, or translucent alpha value in the alpha channel of the color map.)
Another texture that is recognized in the material as either an emissive texture or a detail texture (a material can only have one or the other). Emissive is self descriptive. A detail texture, on the other hand, is a color texture that fades in when the camera gets within a set range. To avoid repeating patterns, this detail texture is not rendered when viewed from a distance.
Physics
Ares Engine integrates the prestigious Jolt Physics library as its default physics system. The world manager intelligently caches new collision bodies for Tokens that are preparing to spawn into the world to maximize overall performance at run time.
Netcode
Ares Engine will include a netcode solution based upon CodeNet's implementation for the Unity3D engine.
Asset Import
glTF 3D assets can be imported into the game, including meshes, nodes (and joint information), animations, and textures. Future enhancements listed in the roadmap include importing other asset formats (e.g., FBX).