During the spring I’ve been exploring the possibilities and potential directions that a completely redesigned renderer could take. Continuing from part one, this post contains more of the results and related thoughts about where things could and should be heading.
When it comes to graphics, things sure have changed since the beginning of the project. Back in the day — almost 20 (!) years ago — GPUs were relatively slow, you had a few MBs of VRAM, and screen resolutions were in the 1K range. Nowadays most of these metrics have grown by an order of magnitude or two and the optimal way of using the GPU has changed. While CPUs have gotten significantly faster over the years, GPU performance has dramatically increased in vast leaps and bounds. Today, a renderer needs to be designed around feeding the GPU and allowing it do its thing as independently as possible.
With so much computation power available, rendering techniques and algorithms are allowed to be much more complex. However, Doomsday’s needs are pretty specific — what is the correct approach to take here? During the spring I’ve been exploring the possibilities and potential directions that a completely redesigned renderer could take. In this post, I’ll share some of the results and related thoughts about where things could and should be heading.
The spring months have been a little crazy with various Real Life time sinks preventing me from delving too deep into fun coding. Consequently, there has been little to no progress with the tasks on the roadmap, such as the multiplayer improvements for version 2.1. Given that several months have passed, it will be challenging to find motivation to restart this work. I am tempted to make some changes to the roadmap to get things rolling along again.
I have managed to steal away some time to explore an exciting new direction for the renderer, though. The basic gist of this effort is to completely revise how the game world is drawn, bringing it up to par with the recently redone 3D model renderer.
Last week I was fixing some regressions and tweaking the UI. Audio plugin selection GUI was brought back as part of the Audio Settings dialog. Continue reading Audio plugin selection
The final week of 2015 turned out to be quite prolific.
There was a new stable build on Friday: 1.15.7.
I made a little bit of progress with animating player weapons by introducing the vanilla-style walk bobbing for the new model renderer. The final missing detail now is to improve how the weapon is positioned, so that FOV and viewport size changes don’t so easily move the weapon out of view. This has always been a bit of a problem with the old model renderer, so doing it better this time around is important.
I continued last week’s work on reflections by incorporating cubemaps to each of the default shaders. Cubemaps can now be put in packages and loaded as assets: there is a new asset type for environment cubemaps (texture.reflect).
It turned out part of the confusion last week was due to some mistakes I had made earlier in how light directions were being passed to and calculated in the shaders. This was causing artifacts such as specular highlights in the wrong places on the model. While fixing the shaders, I also managed to streamline them a little and remove excessive texture lookups.
Overall, we are now getting closer to calling the shaders feature complete. The next step is to apply some final adjustments so that lighting on 3D models will appear natural yet distinctive. However, a big part of making models look good is tuning all the shader and material parameters correctly for each model asset. It is quite challenging to do this if one only has a text file and the appropriate values have to be found via trial and error. Therefore, I added a new editor sidebar for making adjustments to 3D models. I got a nice head start on this by reusing a bunch of code from the Renderer Appearance editor.
The model asset editor should provide all the tools for perfecting how a 3D model appears in Doomsday. It shows basic information about the model file and allows interactively adjusting shader variables, enabling and disabling rendering passes, changing materials, and trying out animations. The editor will not write definition files, though, it just allows finding the best parameters. This is partly because the definitions may incorporate Doomsday Script, and partly to ensure that one can’t accidentally mess up the parameters of a model.
This week’s festive screenshot shows a bunch of test models that I’ve been using for developing environment mapping for 3D model reflections. While the current map renderer is not efficient enough for rendering cube maps on the fly, 3D models will be able to benefit from manually prepared cube maps.
This has been an interesting implementation challenge. It turned out the code I had previously written for transforming objects was not quite compatible with how cube maps needed to be rendered. I thought I was being clever by setting up player weapon models directly in view space, since they are affixed to the camera. For a while I was getting confused by all the different transformations needed for moving between tangent, model, world, and view space coordinates (cube maps are defined in world space). Models already in view space needed to be handled differently than objects in world space.
Eventually I decided to scrap that approach and wrote some new code that positions all models in world space, so their lighting and reflections can be done in the same way. This was much easier to get working correctly. K.I.S.S. wins again!
I’ve also been making some bug fixes for the upcoming 1.15.7 patch. Noteworthy fixes include support for Freedoom’s FreeDM multiplayer IWAD as a recognized game, and correct handling of command line options in the Shell app. The same fixes are already available in the 2.0 unstable builds.
This week’s screenshot shows a work-in-progress version of veirdo’s beautiful new Sapphire Wand model for Hexen. It takes advantage of the new model rendering features such as random alternative animation sequences, animated shader variables, and custom GL parameters for drawing layered effects.
On the topic of weapon models, the new renderer still lacks the vanilla-style walk bobbing. That shouldn’t be a lot of work to implement, though. After some additional weapon position fine-tuning this should be ready for prime time, and we can start preparing some models for distribution and use with the 2.0 builds.
As planned, last week I was working on a better way to load shaders from packages. I managed to complete the improved functionality as planned: when any package is loaded, it is checked for shader definitions; if found, the shaders are added to the runtime shader bank. Similarly when a package is unloaded, its shaders are removed from the the shader bank. Now there is no longer any special case logic needed for the net.dengine.client packages, as their shaders are loaded the same way as shaders from any other package.
I then proceeded to add a way to customize shaders using macros. Like C, GLSL allows defining macros for the preprocessor. This enables injecting custom code at compile time. For example, let’s say a model wants to continuously scroll its texture. This could be done using Doomsday Script, however one would need to keep restarting the script at regular intervals to keep the animation going — not the most efficient way to do things if you have a lot of objects using the model. However, if the model injects a line of code into the model shader for modifying its UV coordinates on every frame, all the work is done cheaply by the GPU. And even better, if the shader is later updated (for example when the user installs a new version of the engine), the model has a much better chance of continuing to work correctly.
Click the screenshot below for a short animation:
Naturally model packages can also provide their completely custom shaders that do not depend on the net.dengine.client shaders in any way.
I was also briefly obsessed with improving the formatting of log entries. There is something about formatting text that manages to hook me every time. The most visible changes are that the so-called “log sections” that contain contextual information about where a log entry was created are now placed within square brackets. This should improve readability. In the doomsday.out/runtime debug output, the content now uses better alignment to visually indicate which entries belong together.
#1815 200.594 I (v) [BindContext] 'global' cleared #1815 200.594 I (v) 'deui' cleared #1815 200.594 I (v) 'console' cleared #1815 200.594 I (v) 'message' cleared #1815 200.594 I (v) 'chat' cleared
This week my primary attention has been on figuring out an approach for handling v1.x style resource packages (PK3s and Snowberry boxes) natively in Doomsday. On the side I’ve been working on dynamically loading and unloading shaders from Doomsday 2 packages.