I've made a game engine in C++ over the course of a few months. Its features include Physically-Based Rendering and Lua scripting support. I later used it to make a game.
The engine uses an Entity-Component-System architecture, optimized for data locality and performance. Each entity is just a 64-bit ID that ties together various components. For each type of component there is a component pool that contiguously stores all components of that type. Iterating over a component pool is cache-friendly and blazing fast.
Component pools are based on sparse sets, so accessing a component given an entity is O(1) in time. Because of using separate collections for different component types, filtering through entities which have specific components is incredibly fast and efficient.
For convenience, it's possible to manipulate entities through actors. An Actor
is a thin wrapper around an Entity
and a pointer to the Engine
.
Here's the same example from earlier, but using actors instead.
There is a unified system for managing resources of practically any type. You can get or create a resource using a string key and a sequence of arguments for a loader. If a custom loader is not provided, the correct way to create the resource from the given arguments is determined at compile-time using template metaprogramming.
The engine features full Lua scripting support. It's possible for Lua scripts to create, destroy, and modify actors and their components. It's also possible to attach behavior scripts as components. This snippet creates a camera and makes it move back and forth smoothly.
The engine supports Physically-Based Rendering using the Cook-Torrance BRDF with the GGX microfacet distribution function. Per-fragment material properties are supplied by these texture maps:
- Albedo
- Joint Metallic-Smoothness map (red and alpha channels)
- Ambient Occlusion
- Normal map
The engine uses layered rendering for shadowmapping to get the same number of draw calls regardless of the number of lights in the scene. Instead of having a draw call for each face of the cubemap of each point light, only one is needed.
Models that are marked static and have the same material are pretransformed on the CPU and merged into a batch. This dramatically reduces the number of draw calls needed to render a frame.