Kerbal Space Dev
The Story of KSP — KSP 0.4

Continuing with the story now, KSP 0.4 was when we first decided to tackle the big problem of terrain, in a planet-sized scale.

I had been playing for a while with creating procedural things here, but they were pretty simple back then. I built this very simple asteroid generator here, mainly to prove to myself I could do it:

I later built a noise-based terrain demo, but it would only create a flat world:

The terrain system you see above did things using mesh tiles that would follow the player around, ‘leapfrogging’ over each other so that as you moved, the terrain farthest away from you would be moved forward, and you could go on infinitely with this system. But while cool, these square tiles would only work in a flat world, so we needed to think of something else.

We needed something that would work for a round planet, and that’s when things started to get a little problematic. 

If you look around the internets for procedural terrain systems, you’ll find thousands and thousands of half-finished attempts, and about 99% of those are meant for games where the world can be flat. There are very, very few projects out there that have actually tackled the problem of generating planets, and the ones that did were very much over my head at that time. 

I was starting to feel I had bitten off more than I could chew with this one. But the game couldn’t go on without a terrain system, so I scrounged up the most of my brain I could, and came up with something that, well, it did kinda look like terrain at least, and it was round. 

It even had an atmosphere to it. This was done with ‘atmospheric scattering’ shaders, which were made accessible to the world by a guy called Sean O’Neil, who wrote an article about that on a developer publication called GPU Gems. Because of that, there were several atmo-scat shaders out there to use. They’re very fiddly to work with, but after a few days of tweaking, we ended up with this:

This terrain system worked in a more or less similar way to the flat tile-based terrain. It used a noise system called LibNoise, which is a library you can download, and for which I found a Unity-friendly version, to give you a plug-and-play style noise generating toolset. It can do very amazing things, if you don’t need to worry about performance.

In the flat world, converting this numerical noise into a terrain was pretty simple. We’d get a noise value from LibNoise for any given position in the world, and we’d push vertices upwards by that amount. 

For the planet thought, things aren’t that simple. For starters, ‘up’ is a very relative term when dealing with round things, so we can’t move vertices ‘up’ anymore. We have to ‘push’ them away from the center. Ok, not too much worse, but if you have a square set of tiles, how do you get those to wrap around a sphere? Ever tried giftwrapping a football? It’s more or less the same issue.

My ‘solution’ (for lack of a better term) was to not use tiles at all, but a single, huge disk, that I had created in 3Ds Max. It was tessellated in several steps, so the center of the disk had a much higher polygon density than the edges:

The idea behind this scheme was that the disk would follow the player around, and it would get larger if you went higher, and lower if you went closer to the ground. Because the disk was always just below you, the ‘tiers’ of mesh detail would work as a crude LOD system.

It worked, to some extent, but there was a big problem. That disk mesh there had about 19,000 vertices on it, and by itself, unity was pretty ok with keeping them updated on every frame. The problem was that you needed to be able to collide with the terrain, and making that whole thing collision-enabled was simply impossible. Unity goes pretty fast until you need to use collision meshes on things that are changing shape, and that’s exactly what we had here.

The solution for it was to let the terrain do it’s thing, and maintain a much smaller collision ‘area’ just under the player. It was invisible anyway, and small enough to run with good frames. 

Then there was another issue. Because the terrain was a disk, it’s vertices could potentially end up anywhere in the world, and that meant something very weird could (and did) happen. If on one frame a vertex was sitting on the top of a mountain, on the next one, it might be half-way down it’s slope, and there’d be no other vertex on the top. That means that as you went along, the terrain shimmered and wobbled because the noise ‘field’ was much more detailed than the mesh.

The fix for that was to have the whole terrain only move if you went past a certain distance from it’s center. By reducing the frequency of terrain updates, it was less apparent that the terrain was wobbling the way it was.

So at the end of that update cycle, this is what we ended up with:

We used two disks here actually. One for the terrain, and another for the water. The textures were being handled by a shader I scrounged up from the internets and modified until it kinda worked. On this shot, you can actually see where the terrain disk ‘ends’ and the far-away planet begins.

The far-away planet was another solution that had to be added. Because the terrain disk was ‘finite’, eventually it needed to be replaced by a less complicated visual representation of a planet. That was done by having a simple textured sphere placed ‘under’ the disk-terrain, and have it drawn to the screen before the terrain was. That, coupled with a terrain shader that could fade away as it went farther from the camera, made for the first version of a planetary terrain that actually met the basic requirements.

We were to find out later, that this system didn’t actually meet all the requirements. But that’s another story for later. For now, we were content with what we had, and started to think about actually bringing the characters into the game.

Cheers

Blog comments powered by Disqus