In the past couple of
weeks months I’ve been doing some clean up process for most of the code I’ve written during the big rendering system refactor in order to make it production-ready. Part of that process is to start making some choices that are going to have a major impact in the future of the project (at least for Crimild v5.0).
Here are the biggest decisions I had to make so far:
Deferred vs Forward
For years I’ve been using a (mostly) forward approach for rendering objects that are affected by lights. That is, each object has a shader that not only calculates its color, but also compute all of the lighting equations. This is the traditional way of rendering and, as the number of lights increases, so does the rendering time. Plus, it needs to evaluate each light for each pixel regardless if that pixel is actually visible or it’s occluded by another object. Simply put, it does not support a high number of lights.
I always liked the deferred approach, where we split the rendering process in two: one pass will render all objects without lighting, while we do the lighting calculations in a separated process. Deferred rendering does support a lot more lights, but has other drawbacks like having to render transparent objects in a separated pass or more memory requirements, but it’s still a lot better than what I have right now. Plus, it’s used in a lot of modern games and engines.
I gave it a try a few years back, but never really had “official” support in the engine. Now, I finally made the call and I’m going to start using deferred rendering from now on. Overall, it should keep things simpler in the long term and should help me introduce real-time ray tracing some day.
I’m aware of other, more modern, approaches like Forward+ or Clustered Rendering, but those are too complex for Crimild at the moment. Due to the modular nature of the new frame graph, implementing such technique in the future should not represent another big refactor of the entire rendering system. So, I might give it a try next year.
Another decision I made is to stick with Physically-Based Rendering (PBR) for lit objects as the only lighting solution that comes bundled with the engine. For years I attempted to maintain both physically-based and traditional (specular/Phong) lighting solutions, but there’s no point in doing that anymore since PBR is the current standard.
Of course, custom lighting solutions are supported if needed, but from now on I’m not going to be one having to maintain them.
Better glTF Support
The glTF file format has been around for quite some time now and it has become the standard for handling 3D assets.
At the moment, Crimild depends on the Assimp Library in order to load glTF models, but I’m going to change that sometime in the near future since Assimp is pretty big and I’m using only one of the many file formats it supports. Plus, it generates a lot of warnings when compiling, and nobody likes warnings.
I would love to have a glTF loader that is part of the Core module, just as the OBJ loader is. Reading glTF (either JSON or binary formats) is relatively easy. The real challenge lays in the fact that the Core module must be written in ANSI C++ and it must not depend on any external libraries. Then, I’m going to implement my very own JSON parser, which is not a simple task. I guess I’ll stick with Assimp for now.
This has nothing to do with Crimild, but it was definitely the hardest decision of all…