As I’ve mentioned in previous posts, I’ve begun work on a new project that likely will be some kind of follow-up to Starcom: Nexus. For this week’s update I thought I’d do a technical discussion of one of my efforts.

Unity has been making some big changes to the engine to support a more performant Entity-Component-Systems model, which they call DOTS (Data-Oriented Technology Stack). Based on my investigations to date, I don’t think the overall system is close to ready for production. It does work, but the documentation is currently extremely sparse and bugs are common. Hopefully that will improve later this year as the technology matures and Unity can devote more resources to documenting it.

Still, this week I was able to implement one feature from Starcom: Nexus using Unity’s new Job System. In the original game, most of the planets have procedurally generated textures produced by combining 3 different base textures using a color map which I call a “thermal map” because it sort of looks like heat vision. It starts with an image like this:

“Thermal” color map

That image is passed to a shader which uses the red, green and blue components to selectively blend three different textures that represent the low, medium and high elevations respectively. The shader does some other stuff as well, but the bulk of the procedural aspect comes from the generation of the above image.

The end result looks something like this:

Or this…

The thermal map is generated using the diamond-square algorithm. This relatively simple (as far as procedural generation goes) algorithm produces a pseudo-random grid of values with some very convenient properties:

First, and most importantly, it is a nice approximation of an elevation map. It can be made to wrap-around. Using the same seed, it will always generate the same output. This means that we can end up with an arbitrarily high resolution image but only store a single integer. We can adjust the resolution without changing the overall output: if we start with a 128×128 texture map, then later switch to 512×512, it will look like a higher resolution version of the same image rather than something wildly different.

A downside is that it is not super fast. Generating a 512×512 texture map involves iterating over a quarter million coordinates, each of which also involves averaging four other coordinates and a separate R, G, and B evaluation. On my machine I think it took maybe a dozen milliseconds. Not a lot, but if you suddenly need to load a dozen planets, it would produce a noticeable stutter in the frame rate. In the original game I implemented the algorithm as an IEnumerable so that the task could be spread out over several dozen frames. But it still happened in the Unity Main thread, which meant it was potentially competing with other operations.

Enter the new Job System. Jobs have the advantage that they allow game logic to run in separate threads, like Unity’s internal rendering system and physics already do, but without the developer needing to worry (as much) about the nightmare of race conditions.

I decided that the diamond-square algorithm was a good candidate to try out this system.

Here is the component in its entirety, warts and all: