When I woke up on the morning of January 2nd and checked my email messages, I found a nice present sent to me by Sebastian Macke.
But first, who is Sebastian? He is the guy behind the Starflight reverse engineering project that you can find here on GitHub. I stumbled across this project while looking for data relating to Starflight in November and immediately reached out to him to see if he could help me out. This project is awesome – he basically created what is essentially a Starflight decompiler that will take the Forth bytecode from the binary program, and convert it to C code. Unfortunately, he is not far along enough in his project to be able to give me the information I needed, as many of the function names are still obfuscated Forth command words.
Fast forward to today. In the email, he wrote that he was able to gain access to the fractal planet generator in the original game! He went ahead and generated the raw height and color map for all 811 planets in the game, and sent them to me. What a nice surprise! The height maps he had sent me were of much higher fidelity than what I was able to extract from screenshots of the game. So, obviously, I had to incorporate this treasure into the fractal planet generator that I had developed for the remake.
You might want to refresh your memory at this time – go ahead and visit the original planet generator post here: https://bravearmy.com/starflight/2018/10/01/final-planet-generator-non-gas-giants/
Okay, so the first step was to bring in the height and color maps that Sebastian made:
Note how there are smooth transitions in the grayscale height map which is the top half of the image? There are so many levels in that greyscale map. Compare that to only 6 levels in the color map in the bottom half.
The next step is to add some padding to the top and bottom of the map to avoid the pole pinching issue, as was described in the original planet generator post:
Now, here we do something a little differently compared to how we were doing it with the original planet generator. Because of the low fidelity of the original elevation data, I had to come up with a custom way to scale the maps up – creating a “contours” pass and a specialized scaler. Now with the higher fidelity elevation data, we do not need to do any of that. Here, I just use standard bicubic (Hermite) scaling to bring the elevation map to 2048 by 1024 resolution.
Below is an image of the elevation data but colorized so it is easier to see the fine details. It is really hard to see details in a straight grayscale map. In these images I use the green channel for the straight elevation, the red channel is the elevation wrapped around 16 times to show banding, and the blue channel is “on” where the elevation is below the water height, and “off” where it is above.
Next, I create the mountains the same way as I previously did with the original planet generator. Very little has changed – it’s the same mountains generator. I build the mountains above the water level, making the mountains bigger in the higher elevations.
Now, I run the hydraulic erosion simulation process. Again, nothing has changed here… its the same process with the previous planet generator. Now we end up with this elevation data:
Now that I have the final elevation data, I generate a “difference” map which is the difference in elevation between the bicubic scaled elevation data, and the final elevation data. This allows me to store high fidelity elevation data at in far less space compared with saving out straight floating point data.
Finally, it is time to create the actual game texture maps from this elevation data. I have much improved this part of the process.
First, the albedo (color) map. Instead of translating the elevation directly into colors, I use a dithered version of the original color map. This allows for more variation in the coloring of the terrain. Secondly, (and this is new) I bake in the ambient occlusion into the albedo map. What is ambient occlusion? Basically, it is darkening the parts of the map that gets less light, such as where there are creases or valleys. I think this made a huge improvement to how planets look. Finally, I color the map where there is water. The water coloring process is also different and much improved as well. In the shallow water areas, I allow more of the soil and mud to show through. I could not do this with the old elevation maps because I had no elevation data below the water level. Here is the result:
Here is the normal map generated from the elevation data:
And the specular map:
And the water map mask:
Put it all together and we get this…
These images are actually 4k images (yes, you can run Starflight in full resolution on 4K and 8K screens!) which will allow you to see the planets in better detail when you zoom onto them. To do that, click on the image, and then when the image pops up on your screen, right click on it and select the “open in new tab” option. This will open the full-sized image into a new browser tab, and in that tab, you are able to zoom in. You can also download them to your computer.
Here’s another one…
And here is what Arth looks like now…
I am pleased with the results!
There is some room for improvement – for example, I can zero out the difference map where it’s too far below the water level to make any difference. That will allow these difference maps to be compressed at a higher ratio, saving some space on disk. But I have been putting off doing that because it takes roughly 24 full hours to regenerate all of the 811 planet maps, and that’s on my 10 core Alienware machine (yes, the planet generator is multithreaded).
You may also have noticed in these screenshots something else that is new… atmosphere. I have gone ahead and added an atmosphere effect to planets in the game – there is a halo around planets where the atmosphere is and the color of the halo depends on what gases make up the atmosphere for the planet.
Here is a bonus image – one of a gas giant. I had just realized that I was talking about my planet generator which does it’s magic only for solid planets. What about those gas giants in the game? I do just a simple blur – a ton of blur on the X-axis and only a little blur on the Y-axis. That gives me this:
And that is the end of this blog post!