There are quite a few game engines out there: from the very popular Unity, to the technologically advanced Unreal Engine, but there are also recent contenders like the open source Godot Engine. Personally, I've worked with most of them in the past and really want to like open source projects like Godot... but is it ready? Today, I set out to have a quick litmus test by attempting to get heightmap terrain functionality working in the engine!
As with my previous article, I've also experimented with making a video for this one, so you can have a look at it on YouTube:
See below for a slightly more detailed walkthrough of the whole process...
My idea was fairly simple: to take the terrain data for my entire country and to get it working within the game engine. This could be useful for not only trying to create video games, but also any visualization tools that I might want in the future. The Godot engine has proven itself to not only be capable for entertainment purposes, but also creating some productivity tools, so this could also be a test for seeing how viable importing real world data into it is:
Even if we are talking about video games, being able to display large terrains in real time, and eventually dynamically load and unload them, as the player moves across the landscape, is a pretty useful feature to have! After all, some of the games out there do indeed allow the players to explore large landmasses:
What if I could create something like those games, but set in the locale of my own country?
While we don't intend to create anything that'd actually compete with those other games per se, it's still an interesting setup to explore! Granted, getting the heightmap data isn't the hard part - rather, it's the fact that the image we get is a little bit too big to be loaded into the game engine directly:
Thankfully, it's not too hard to split it into smaller chunks, which could then be processed by the game engine as needed (the ones nearest to the player loaded in, the rest unloaded). The easiest way I actually found was to use an online tool, although there are other ways as well, as long as you don't mind a little bit of scripting (e.g. using ImageMagick):
Once this is done, we get separate image files, each of which would correspond to a terrain object in the game engine:
As for the sizing of everything, it really depends: games that aren't flight simulators rarely go for 1:1 scale, because most games that attempt this end up feeling quite empty, even with procedural content generation. It mostly depends on what feels good in testing, for example, if we split the terrain into 7x4 pieces, then we might have each piece be 1x1 km big, which would make for a decent game world, as long as there are enough things in the game world to catch the player's attention.
But perhaps I'm getting a bit ahead of myself... because Godot has no official terrain support.
Exploring terrain functionality is understandably a bit of a problem, if there is no terrain functionality in the engine! This is one of the reasons why other projects like the Stride game engine are not what you'd reach for, if you'd want to work on certain kinds of games. Thankfully, in the case of Godot, we actually have a community addon for heightmap terrains. Not only that, but it's also one of those rare cases with open source projects, where you get some really good documentation, so that it's clear how to get started with it, even if it's a 3rd party solution.
This is certainly a situation in which the engine being both open source and with good support for addon creation is a really nice thing to have:
While Godot has an asset library where you can get all sorts of plugins for the engine, as well as assets to use, sadly it isn't as big as the likes of Unity, probably because the latter is a mostly commercial effort where a lot of the assets are paid. But hey, sometimes community is able to contribute the missing pieces that you need, completely for free, though it remains to be seen how well this will work long term.
In addition to the addon itself, we also want our terrain to actually look like ground, so getting free textures for development is also a nice idea. After that, it's mostly just a matter of importing the heightmap data in the editor, setting up the textures, to get something like the following:
Admittedly, the quality of the heightmaps isn't too good: I even ran some blur filters in GIMP against them, but they still get imported as somewhat jagged and uneven, although this might also have something to do with the limited accuracy of PNG import, because the RAW format seems more popular for heightmap data (which conveniently also doesn't work with GIMP and Godot, for some reason).
However, so far things still seem nice - we get the terrain in the editor, everything seems fairly usable and the Godot editor runs pretty well with low resources, so it should be a success, right? Well, no, because once we actually run the project, we get lots of issues...
Sometimes things seem to be too good to be true and this was definitely one of those. While things initially worked well enough, actually running the project revealed jarring visual bugs. As I moved the camera around the map, there were blank squares popping in and out, where the terrain was supposed to be:
This wouldn't be the biggest issue ever, if it'd only happen occasionally, but what I saw was it happening almost every other second. This sort of bug is extremely annoying and was visible both when running the game in the editor, as well as when running it as an exported executable. While I can't say for sure whether it was caused by my GPU (which doesn't seem to have issues otherwise) or a bug in the renderer itself, I can at least make a guess about what is the cause for this: the LODs.
You see, there is nothing magical about the terrain representation in the game engine. It's still a 3D model and thus is made up of lots and lots of triangles. If we tried displaying all of the data at full resolution, most of the consumer hardware out there would run into issues. That's why the terrain is typically split into chunks (even if you have multiple separate terrain objects) and level of detail meshes are generated - versions of the data at a lower fidelity. Then, the chunks that are further away are shown at a lower quality, because you're less likely to notice, while the stuff that's nearby can be shown at the full level of detail, giving you the impression of a good visual quality:
For whatever reason, in Godot 3, there is some sort of a fault in the process of replacing chunks and as a result we get those visual artifacts, which is essentially a gamebreaker for me, both literally and figuratively! Thankfully, switching to Godot 4 solved this particular issue for me: though I would have much preferred to keep the game compatible with the older versions of OpenGL instead of having to opt for the Vulkan renderer, that, while visually impressive, also needs more recent devices to work.
Either way, that's the cost for getting anything at all working in this case:
Except that it still isn't enough. You see, I ran into a few more issues which were really annoying and also might be pretty hard to hide or deal with, both on the development side and when actually playing any sort of a game. The first one was that the different heightmaps of the adjacent terrains weren't stitched together, which lead to visible gaps (that would also let physics objects fall through):
In the real world, you don't always get ideal data that the engine will be able to import without such issues. Most mature game engines will have tooling for automatically or manually stitching such adjacent terrain pieces together to get rid of these issues, yet the terrain plugin for Godot doesn't have that as of yet. While it most likely would be possible to write a script that just runs in the editor and does this for me, doing so is still not a trivial matter.
Next, I also wanted to use normal maps for the ground textures, because that can really make them look a bit more detailed, if you can get the additional data. Here's a slightly different example, where I use normal maps in Blender, to make a coin appear less flat, as if light is bouncing off of its surface:
The coin on the right has normal maps enabled, but the one on the left has them disabled. Even at very low fidelity (going for a pixellated look), something like that can definitely make a difference, especially because the technique is not too computationally intensive and the surface can remain completely flat, thus saving resources. This would make the grass, mud and rock textures that much nicer in the engine, however Godot decided to use normal maps for one terrain, but not use them for the adjacent ones, leading to everything looking like this instead:
Once again, that is something that nobody could really ignore and thus is a deal breaker, especially because there wasn't a single error message in the console, thus making me think that the plugin thinks that everything is okay. This would surely make actually figuring out what caused this issue way harder. There were also some editor bugs, such as trying to paint a texture on one part of the terrain, but there being some odd offset, painting somewhere else instead:
With all of that happening within the first day of trying to get a simple terrain up and running, the question then becomes: should you even use Godot?
The answer, at least for now, is simple:
No, you shouldn't use Godot for your projects, if what you want is terrain functionality.
While your experience might differ from mine and things might just magically work (possibly with a later version of the plugin, where some of the bugs are discovered and fixed), in my case it doesn't make sense to either make multiple different bug reports for pretty severe issues, or spend weeks trying to learn and debug every single one of these broken bits of functionality.
Yet, I haven't really paid for this, so complaining wouldn't be entirely fair of me either: after all, a lot of the open source software out there has issues being financially sustainable, so you should definitely applaud the efforts of the community to get anything at all working. They have a solid start and I actually believe that they'll eventually get to a reasonably stable implementation without all those issues.
However, saying: "Oh, it's going to be better in X months!" is a non-answer. What do we do today, to get things working? The answer there is also simple, if a bit disappointing:
Just use Unity.
It's not open source, the install size is huge, its performance isn't too good, the features that they release in the recent years are kind of broken and unfinished... and yet, the essential functionality you'd expect from it actually work. All that you need to do is admit that it's a bit too early for Godot and then you, too, can have working terrain with no seams or other texture weirdness:
Admittedly, the terrain import still had those issues initially, but using the smooth feature solved pretty much all of those issues instantly. Not only that, but the terrain tools can actually work for adjacent terrains (e.g. do smoothing across the borders) as opposed to Godot which has no such features:
In addition to that, you still get an out of the box terrain LOD solution, there's an even bigger asset store than what Godot has (because Unity has lots of commercial offerings, too), you can still use C# as a development language and everything is just okay... as long as you can ignore all of the unfinished or broken features, which deserved a little rant in the linked video above. Feel free to give it a watch, if you want to learn what I think are the drawbacks of Unity.
At the first glance, it might seem a bit harsh of me to say that you should just use Unity, or another engine like Unreal with commercial incentives or a huge corporation behind it. Personally, I think that I can still enjoy Godot for the kinds of projects where it makes sense (notably, it's really good for 2D games or quick prototypes because of GDScript, as well as doing development on older hardware) but recommend that people use whatever works for their goals, even if that means sometimes using other options.
There is no shame in going with the mainstream option or even doing something like opting for an operating system that has proprietary code in it, just because you want everything to work, as opposed to handicapping yourself just because you want to support the free software movement and some of the FSF ideas. In other words: "It is what it is, use whatever works." Which actually is a little bit funny, because the video also showed that Unity isn't without a fault either, that there were also things that felt broken in it as well.
The difference is that Godot and the terrain plugin are open community efforts and might eventually be picked up by someone that really wants to solve these particular issues (if they run into them) and at some point in time it might be the best implementation out there. Of course, whether that actually happens, only time will tell. For now, it's a bit too early for terrains in Godot, at least for me. This article might also fit under the "Everything Is Broken" section of my blog, but I think that sometimes it's nice to also talk about the fact that not every technology out there will be suitable for every purpose and that exploring alternatives is perfectly fine!