In these last few days I have merged a huge internal refactoring into Gaia Sky’s master branch. This refactoring has been cooking for several months and has adapted or completely replaced virtually every piece in the code base. Read on if you want to know more.
Entity component systems
Up until very recently, the internal model in Gaia Sky was implemented with an OOP inheritance hierarchy with
a baked in scene graph and octree. The model was huge, with an object called
SceneGraphNode at the root and a
deep structure that went down several levels and some 50 different object types. Maintenance was difficult,
and the addition of new types was even more challenging.
It was clear that a new model was required, and I immediately looked at entity component systems (ECS).
ECS is essentially an architectural pattern often used in video games. The model is based on entity objects, which are
only bags of components, which hold the data, and are processed by the systems, which contain the logic. An entity is
ideally defined by its components only. Systems operate on entities depending on the actual components that they
hold. This paradigm is very convenient, as it replaces inheritance with composition. You can create entirely
new objects by just grouping a bunch of components together.
The work was split into phases:
- The first phase moved the JSON loading and recreates the whole structure into entities and components.
- The second phase moved the logic in the scene graph objects into systems and achieved a fully working build.
- The third phase also incorporated the current renderer into the ECS structure.
- Once everything was in place and working, we removed the old model.
Once this was implemented, the code base became wildly different and much more maintainable. It enables easier parallelization in two different ways:
First, some of the update systems can run in parallel. When the first top-down update of the scene graph has been completed, the rest of the update operations can essentially be run in parallel. This wasn’t possible with the old model, as the update operation was monolithic and sequential for all objects. Second, it will possibly enable concurrent update/render processes (i.e. run the update thread separate from the main render thread). Before, the update/render cycle ran in the same thread:
render 1 and
update 2 tasks can be made concurrent:
Since the model is being rendered and updated at the same time, this required the introduction of an extra ’extract’ step, where a representation of the scene containing the information to render is extracted to send into the render system. Once this extraction operation is done, and since the render system reads the extracted data only, the next update cycle can start safely.
Scene graph integration
In the ECS model the scene graph is contained in a
GraphNode component, which
contains the tree structure as a list of references to the
instances and the
GraphNode parent, if any. Additionally, the root node
has a special
GraphRoot tag component. Since the scene graph needs to be
processed from top to bottom, we have a system which acts on
(we only have one), and processes the whole tree. This is the first update
operation. The rest of the update operations are implemented in other systems.
Large star catalogs in Gaia Sky are backed by an octree which distributes
stars spatially and hierarchically according to magnitude. This is implemented
in very much the same way as the scene graph. We have an
which contains the root of the tree. An update system runs on entities with
this component (only one usually), and updates the octree by computing the
visibility of each node and updating the objects when necessary.
Try it out
The ECS work is already merged into the master branch, so if you want to try it out you just need to check out the repository and build the project:
git clone https://codeberg.org/gaiasky/gaiasky.git cd gaiasky ./gradlew core:run
The ECS will be a part of the next Gaia Sky release. On top of the refactoring, there are also countless bug fixes and a good bunch of new features.