VEngine 2 (Vulkan/D3D12 Hobby Render Engine)

Having learned a lot from the previous version of my engine, I started work on this new version in early 2021. Instead of diving straight into writing the renderer, I first did a lot of non-rendering work:

  • I implemented a custom entity component system (ECS). The ECS is a so called archetype ECS, because it stores all entities with the same set of components (which define an archetype) in tightly packed arrays. This allows for very cache efficient and fast iteration over components.
  • In order to facilitate multithreading, I implemented a fiber based job system, inspired by “Parallelizing the Naughty Dog Engine Using Fibers” as presented by Christian Gyrling.
  • I also spent some time on an asset manager/system that does loading, caching, reference counting and unloading of assets.
  • For physics I integrated PhysX, which is also used for character controllers in the engine.
  • Skinned animation has been an item on my list for quite a while, so I took the time to finally implement this feature. While still far from animation systems in proper game engines, it does support setting up blend trees using a node graph system. The parameters for the blend trees are controlled through lua scripts. Node Graph Blend Tree
  • Using the physics and character controller provided by PhysX and the animation system I had created, I implemented my first animated and controllable third person character!
  • Since I had basic support for scripts at this point, I went a step further and added a ScriptComponent that can be used to attach arbitrary scripts to entities. Lua scripts can access the ECS, giving them access to most data in the engine.

In late 2021 I finally turned to implementing rendering features. Unlike the previous version, this renderer uses descriptor indexing for all resources, significantly simplifying descriptor set management. Vulkan and D3D12 are accessed through a custom abstraction layer, most of which was inherited from the previous iteration of the engine. Shaders are written once in HLSL and compiled with DXC to either DXIL (D3D12) or SPIR-V (Vulkan). Shader code for TAA, GTAO, Volumetric Fog, bloom and auto-exposure is also taken from the previous version.

  • Synchronization and temporary resource allocation is managed by a simple render graph implementation.
  • I also implemented relightable reflection probes. Each frame the g-buffer of a single probe is lit and then filtered with importance sampling.
  • Very recently I implemented a first version of global illumination based on “Dynamic Diffuse Global Illumination (DDGI)” by Majercik et al.. Unfortunately I do not have access to any GPU capable of hardware supported raytracing, so for now the irradiance probes are generated in a dedicated baking step, where cubemaps are rendered for each probe. Once I get access to newer hardware, I plan to add support for updating the probes at runtime using raytracing. Global Illumination One neat property of irradiance volume techniques such as DDGI is that they can be sampled by Volumetric Fog, enabling very atmospheric scenes with volumetric lighting: Global Illumination affecting Volumetric Fog Global Illumination affecting Volumetric Fog
  • All the basic light types (directional/point/spot) present in the previous version are supported in the new version as well. Shadow maps for point and spot lights are automatically resized to match the resolution of the projected light size, minimizing wasted performance and memory due to undersampling. The system still stands to benefit from caching shadows, which is something I plan to implement in the future.