Some of the regulars will have noticed I've been posting less lately on gamedev. This is because I've been spending a lot more time working on Godot. After making a few games with Godot for the challenges, I had downloaded the source and proceeded to fixing bugs that affected my games. I've now made a few contributions to the engine and spent as much time working on addons / plugins.
It has been quite interesting for me because it's my first venture into open source. I've had to learn (the basics!) how to use git, as the project is hosted on github. I've used various source control systems before but git is a bit different, so that was fun.
Godot Core & Addons
One of the first things anyone wishing to contribute to Godot will learn rather rapidly, is that there is a firm policy of trying to have as many new features as possible as addons (GDScript addons, c++ modules, GDNative c++ binaries), and to only put new features into the core engine if absolutely necessary. This has proved to be a controversial area, because although in theory this is a great plan, in practice it is much easier for developers to get their work available by getting it into the core engine. At present, far fewer users than we would like actively download and use the various addons. Some types of addons require you to be fluent in building c++ to even install.
This is a recognised problem among the devs, and hopefully we will be able to come up with some solutions that make it easier to deploy and install non-core modules. Ideally users would be able to just search and click to install an addon from the IDE. This is to some extent possible with GDScript, but not yet available for c++ addons (which are needed for performance reasons in some cases).
On the other hand, with the amount of developers keen to make new features, if they were all integrated into the core engine, it would rapidly become a bloated and unmaintainable mess. Of course, psychologically every dev feels that their new feature NEEDS to be in the core engine, no matter how niche.
What I have been working on
Initially I was mostly fixing bugs in the Android build. As Godot is multiplatform, and has limited manpower (there are only 2 paid fulltime devs!), one of the areas that is lacking is systematic testing. This is totally understandable, but we mainly rely on the issue tracker for people to report bugs and regressions on the different platforms. This seems to work quite well for windows and linux and iOS, but for Android the problem is that there are a million (literally) different combinations of hardware and OS out there, many of which have bugs.
Initially the plan was for an OpenGLES 3 renderer that would work on all supported platforms. Unfortunately although many devices report that they support GLES3, in practice the implementations can be very limited and buggy, and it was clear that to cover all the bases Godot needed to produce a GLES 2 backend. This is still rather flakey in places even now, but tends to offer better performance and compatibility than GLES 3, particularly on Android.
GLES 2 Skinning
One of the first areas I actually made a difference was in identifying and fixing a major skinning bug in GLES 2. I hadn't been able to get any of my games to run on Android, and it was clear there was a major bug which seemed to be crashing Godot whenever skinned characters were used. Which is like, almost every game. Which meant for all intents and purposes, 3d was unusable for mass market on Android.
What became apparent is that it is a very slow process to investigate these types of issues on other platforms. Every time you want to run a build on a device, you have to compile export templates (a version of Godot engine for that platform), re-export the project, deploy to the device, and wait for feedback in adb logcat. Not very fast. You need a lot of patience.
On top of that I didn't have a clue how Godot engine worked so I resorted to putting a lot of print statements throughout the code to narrow down what was causing the crash.
In the end I tracked it down to the bones data not being present for some reason on the device. After further investigation it turned out that the bone data was retained on desktop, but deleted on Android, and only required in certain hardware configurations (if the GPU didn't support float texture). So I figured out a few lines of code to fix this, and it was my first PR.
As a result my game that wouldn't work before was now working on my tablet and Android tv box. Great success!
Android Keyboard Input
Next up, it was apparent that a large percentage of physical keyboards weren't working on android. Certainly none of mine. A bit of debugging and I had this figured out and fixed. (Unfortunately now they are working it has exposed another bug which causes crash when pressing left cursor .. but am sure we will fix it! )
As some of you may know I'm big on game timing, and had previous written an article about it. I resolved to improve the timing in Godot to help resolve the jitter issues many users were encountering.
Fixed Timestep Interpolation
The problems were occurring because Godot uses a fixed timestep (which is usually good), however if you are using a fixed timestep, under almost all circumstances, you MUST use fixed timestep interpolation to deal with the differences between frame times and tick times. Otherwise you get godawful jitter. Which is what godot currently has by default (unless by chance you match your tick rate to your frame rate).
The established solution is to use fixed timestep interpolation. Which is pretty easy for experienced devs to implement, unfortunately it can be a bit daunting for beginners. So I resolved to try and make this easier. On top of that, there was a more serious problem, the timing information necessary to calculation the interpolation fraction wasn't exposed to users.
I did some experiments at modifying the base Nodes in the engine to automatically handle interpolation under the hood. They were only partially successful .. it worked but it was not pretty because the engine was not designed with it in mind. Instead I developed a purpose built interpolation node to do this without any coding.
For this to work properly I did some investigation into the Godot timing system and worked out how to expose the interpolation fraction. I then made a PR which has been merged which exposes this to the user. Although reduz decided interpolation shouldn't be part of the core engine, he was happy to have the fraction exposed so it was possible in user code / plugins. This is now working great and will be first available in Godot 3.2 which is currently in alpha.
On a suggestion from Calinou I then converted my interpolation nodes (3d and 2d) to GDscript so they could be installed as an addon, which is much easier to deploy as it doesn't require compilation for different platforms (users simply copy the addon to their project folder). I am planning to add this to the official addons once 3.2 is released.
While I was working with the timing and after discussion with reduz he seemed interested in an eventual move to basing the tick rate on the frame rate of the device. With this in mind I set about expanding the timing code to easily add new stepping models, and added a semi-fixed timestep mode. This is now languishing in amongst some 350 pull requests waiting for review .. I think it will have to wait until Godot 4.0 now, and perhaps until reduz takes another look at the timing code himself as he may want to do it slightly differently (at the moment the vulkan renderer is the priority).
I'm not too concerned about this actually, because although semi-fixed is the default timestep in e.g. unreal engine, I really put it in for completeness, and it is not something I'd tend to use in production myself. It is quite useful for beginners though.
More for my own use I also modified the engine to allow delta smoothing. This is a subtle timing problem that can give jitter, and delta smoothing can be used to help alleviate (though not eliminate) the issues of measured delta not being representative of actual frame delta. I suspect this is something that I would have an uphill battle to get merged into core, so no PR for now and I'll wait until the timing issues have been discussed in future.
OS Timing bugs
I also spent a good week investigating something I had never encountered before. We had had bug reports of time going backwards, which prompted me to investigate the values we were getting from the OS clocks. It turned out, that under certain circumstances, the MONOTONIC clocks (that were never supposed to go backward), did appear to be going backward. This could lead to incredibly nasty bugs where time was assumed to be going forward (using unsigned ints to store time difference e.g.).
After much research I didn't completely sort this out. However I am hoping that it is not currently a problem that occurs in the wild on the current version. When you get down to the level of nanoseconds you have to deal with race conditions and mutexes to prevent something else happening between you measuring the time and reporting it. And time, by its very nature, once you have measured it you have the wrong value.
There is a great quote 'Give a man a watch and he'll know the time. Give a man two watches and he'll never know the time!'...
Rooms and Portals
And so we move onto my current project. Many users have been requesting occlusion culling, and it has been sorely missing from Godot since version 2. It has been on the roadmap for a while but got pushed back because of the need to work on Vulkan. The frustration from some of the users has been palpable. Admittedly it does make the engine almost unusable for certain genres of games like 1st person shooters.
So with this in mind, and having written room / portal / PVS systems before (mostly over 15 years ago though!) I decided to have a crack at an interim solution until reduz gets round to it some time during Godot 4.0. I will detail this in a later blog post, and it is still a work in progress but for now here's a link to a video and the project on github: