Huge refactoring in Gaia Sky: ECS

Moving the old inheritance hierarchy to an entity component system

4 minute read

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.

Actual implementation

The work was split into phases:

  1. The first phase moved the JSON loading and recreates the whole structure into entities and components.
  2. The second phase moved the logic in the scene graph objects into systems and achieved a fully working build.
  3. The third phase also incorporated the current renderer into the ECS structure.
  4. 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:

update1
render1
update2
render2
update3
...

Now, the render 1 and update 2 tasks can be made concurrent:

update1
render1
update2
render2
update3
...

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 GraphNode children 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 GraphRoots (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.

Octree integration

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 Octree component, 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.

Website design by myself. See the privacy policy.
Content licensed under CC-BY-NC-SA 4.0.