Sunday, September 8, 2024

Alpha update

Since the program is now running in a mostly stable way, I decided this might be a good time to update the code on github. It's definitely not ready for a proper release so I've not uploaded a built executable, but some people might like to have a look at how it's working. So consider this a sort of alpha preview.

It's uploaded here. The previous version of Undiscovered Worlds, with flat maps, is now Undiscovered Worlds Classic and can be found here, including the executable and instructions.

You don't get the jazzed-up GUI though, because those are changes I've made directly to the ImGui code, so I can't really upload them as part of this project.



Tuesday, September 3, 2024

Parrots everywhere

My spherical worlds are mostly working pretty well now (although for some reason I haven't been able to make river deltas work on them - I don't know why). So it's time to try to get regional-level maps working with these worlds.

As I've explained before, this will work differently from the original, flat-world version of UW. In that version you could view the global map, select a point on it, and zoom in to see the regional map of that part of the world, in a separate screen. But this wouldn't work very well for a spherical world, where we will instead display regional maps directly on the globe itself. As you zoom in, the details of the regional maps will become visible. So it should all operate seamlessly. That's the theory anyway!

This means we need the ability to generate and display multiple regional maps at once. It's not possible to store regional-scale information for the entire planet, since a large world has 16 x 16 regions on each face, making 1,536 regions in all. We can store only a fraction of these at once. So what we need is a system whereby the program can dynamically create new regions as the user moves around the world, deleting them when they're no longer visible.

After many false starts I've got the basics of this system up and running. We have a stable of threads dedicated to generating regions and drawing their maps. As the user views the globe, these threads work in the background to create regions roughly where the user is looking, with unused ones being discarded. Meanwhile, the main thread displays the regional textures where they exist, and the lower-resolution global textures where they do not. This way, if the user is zoomed in enough to make out details at the regional scale, they should be able to see only regional textures visible on the screen.

Now I haven't yet started translating the actual region creation functions so that they work with spherical worlds, because I wanted to get this system up and running first and then plug in the region creation functions as I convert them. So at the moment the region creating threads are just applying a placeholder texture (of parrots, because why not). But here is a pretty rough-and-ready (and somewhat nausea-inducing) video showing the system in action.


As you can see, as we move around the planet (or rotate the planet itself) the more distant regions are deleted and replaced with closer ones. If you zoom in closely, it creates the illusion that the entire world is covered with nothing but parrot images, because you can't see the edge of the patch of textures.

Now all I need to do is to convert the existing region-creation functions from the old version of UW. For the most part this should (I hope) involve changing them so they take their raw data from the spherical world object instead of a flat one. This will be tricky at the edges of faces, because the regions as generated are a bit larger than what you see. This is because some elements of the tiles that compose the regions overlap from tile to tile, so when we generate a region we need to generate the tiles along the edges of its neighbouring regions, in case anything from them overlaps onto our region. In a flat world this is fine, but here we're going to have regions along the edges of faces of the cubesphere, which means we have to take into account the fact that tiles from the next face along might be rotated relative to the active face, and that complicates matters.

That probably makes very little sense. Still, I'm glad to have the framework for regions set up now, so I can focus on getting back to map generation...

Thursday, July 4, 2024

Sprucing up

My plan to create, replace, and delete regional maps on the fly means I need to use multi-threading, where a program basically splits itself into multiple concurrent programs. This is so that Undiscovered Worlds can get on with generating regional terrain while the user is moving around and viewing the world. I've never done this before, so I've been learning how, and fortunately it's not too hard, at least in principle. To practise, I've added a progress bar for world creation - one thread creates the world while another updates the progress bar - and it works quite nicely.

Adding the progress bar made me think again about the GUI. I'm using Dear ImGui, which is a very widely used library, but mostly for internal use rather than user-facing interfaces, because it's pretty simple to incorporate into one's code but doesn't look very fancy. (Also it's easily recognisable!) I certainly don't want to change to a different GUI again, but I thought it would be nice to try to change the appearance of Dear ImGui a little to make it a bit more distinctive and attractive.

So I've had a go at tinkering with the code of Dear ImGui. I've been shamelessly copying the style of NanoGUI, another library that I was using for a while in an earlier version of UW, but abandoned as it proved too tricky to port to Windows. My very rough hacks can't really reproduce its appearance, but I think the results look quite nice:


Hopefully it doesn't look quite so generic now. There is still some tweaking to be done, of course, but the next focus is on getting some version of the regional detail up and running.

Sunday, May 19, 2024

Global details

It's time to think about adding detail to the planets. The ultimate aim is to create regional maps similar to those in the old version of Undiscovered Worlds, but wrapped onto the sphere. My initial thought was to generate an entire globe's worth of these while the user is looking at the globe, adding them on as they are generated - but that is too much detail to hold in memory at once. We need, then, a more dynamic system, which can generate new regional maps and delete old ones as the user moves around the globe, so we only store the ones we actually need.

This creates a problem though. Here again is how the cubesphere is constructed:


If this is a large world, then each of the small panels corresponds to a single regional map. (With small or medium-sized worlds, it's still constructed from the same number of panels, but a single regional map would be spread over several panels - four each for a medium-sized world, or sixteen for a small one.) So as the user moves around the globe, each panel will display either its portion of the global map texture or its own regional map, depending on how close it is to the viewer.

Clearly, for this to work well, we want to display regional maps only when they are pretty close to the viewer. Otherwise we would have to be generating masses of them every time the user scrolls around even a little bit.

The problem is that the global texture looks quite blocky quite quickly as you zoom in. It's just not highly detailed enough to let us get away with generating only very close regions.

The solution is to make the global texture more detailed. Rather than making the world object (that is, the data structure that holds all the information about the world) more detailed itself (as I did once before), I've created a much simpler data structure that only holds information needed to generate the map textures - basically elevation, temperature, rainfall, river flow, and one or two other things. Since it's much simpler than the "real" world object, it can be four times as detailed without taking up too much memory. Once the world is generated, we populate this "simple world" on the basis of the "real" one, mostly using a simple diamond-square algorithm similar to the one used for regional maps. Mountain ranges and rivers are drawn more directly on, to maintain their detail. Then we just use that to create the main world textures. Since the "simple world" is only used for generating those textures, and doesn't contain information that the user can access otherwise, we don't have to worry about details such as carving out river valleys and the like, so it's very quick to generate.

The "simple world" has a resolution of 4x4 the "real" world, which means that the global textures can now be 16 times as detailed. This only applies to the main textures, showing the world pseudo-realistically - the other textures, showing information such as elevation, temperature, etc., remain in the old resolution. So for example, here are some shots of a single area showing elevation, rivers, and basic terrain colours, all in the "true" resolution:




And here is the same area with the higher-detailed texture plus fancy shaders (and clouds dialled right down so you can see the details more clearly):


It's a pretty simple technique, and there are certainly a fair few wrinkles still to be ironed out, but I think the initial results are quite decent:


With this in place, we can now zoom in a fair way before the map looks too blocky. That means that, in theory, we can generate regional-scale maps and apply them to the appropriate parts of the globe only when the view is quite close - so we don't need to display many of them at the same time. Whether it will actually work like that, though, remains to be seen!


Saturday, April 13, 2024

Stars and suns

I've been doing a fair bit of tinkering with the model, focusing on improving the algorithms connected with monthly changes. Seasonal temperatures and rainfall are now more realistic (more or less), and so is river flow. You can also pull up monthly river flow charts alongside those for temperatures and rainfall, to get a better idea of seasonal changes for any point on the globe.

Alongside this, I've removed some bugs with specular maps (rivers now reflect sunlight correctly) and improved the appearance of clouds.

After doing all that, I decided that my planets looked a little lonely floating in the void, so I've added procedurally generated starfields, galactic dust and nebulae, and some bloom effects on the sun, as well as simple lens flares. All of these can be adjusted in the settings. I wrote all the shaders from scratch, as I couldn't find anything quite like what I wanted. This was a pretty tough learning curve, but I'm glad to have managed it and am quite pleased with the final effects.

Here are a few shots showing how it looks now:






All of this means I've more or less run out of things to do before tackling the next big thing, which is adapting the regional map model to the new spherical layout. As I've mentioned before, this is inherently tricky. The ideal solution, if I can manage it, is to generate regional maps on the fly while the globe is displayed, and display them on the globe in the appropriate places as they're generated, if it's zoomed in enough to make it worthwhile. So this would involve keeping a lot of regional maps in memory at the same time, with hopefully a system intelligent enough to generate precisely the ones that are needed, depending on where the user is looking, and deleting the ones that aren't.

That's the plan anyway! If I can't get that to work then I may have to go for a less ambitious system where the regional maps are displayed in a different screen altogether, as with the 2D version.

Saturday, February 3, 2024

The changing of the seasons

Translating my simulations into a spherical context has thrown up an issue that I've had at the back of my mind for a while: how to represent changes over an annual cycle? The colours on relief maps that Undiscovered Worlds creates are determined by rainfall, temperature, and so on, but it always draws the maps on the basis of annual averages. But the program does track variations in these things from month to month. So I've thought for some time it would be interesting to add the ability to generate monthly maps, so you could see, for example, the advance and retreat of the ice caps over the course of a year.

Now that I'm dealing with properly spherical worlds rather than flat maps, doing something about this has rather been forced upon me, because if I'm displaying the world as a sphere in space, with light coming from a particular direction, I need to make sure that it's the correct direction, based on the planet's orbital characteristics. But that will vary throughout the year. In other words, to display the world at all - at least in the pseudo-realistic fashion that I've been developing - I have to make a decision about what time of year it is. And that suggests (a) that the features on the world, such as sea ice, should reflect that time of year, and (b) that it should be possible to change the time of year and see how these things change.

So I've implemented this now. You can change the month, which will affect things such as the sun's angle and distance, the extent of ice on sea and land, how arid or lush the land appears (monsoon areas look desert-like in the dry season and green in the wet season), and even how big rivers are (they swell and dwindle to reflect precipitation, and can also show flooding in times of thaw). Cloud cover can also vary depending on precipitation, although it doesn't change otherwise.

For example, here is a world shown in January:


And here is the same world in July:


You can see how the features have changed to reflect the seasonal changes. Also note that the camera angle remains constant even as the planet shifts relative to the sun - you can set the camera to remain in the same place relative to the planet when making these changes, or you can detach it and watch the planet rotate beneath you.

Here is a more zoomed-in series of shots of another world, showing the changes month-by-month from January to July. I especially like how you can see the snow creeping down the mountains as winter approaches. Notice also how the bit of land in the bottom left-hand corner has a fringe of sea ice around it all year round - this is from the sheltering effect of the land itself, which encourages ice to form in temperatures where it wouldn't be possible in more open ocean. The same effect causes the ice cap to seem to reach up slightly towards the main continent as it moves north in the colder months.








[EDIT] I only realised after posting that the sun here is moving in the wrong direction - shining more directly on this hemisphere in winter! This is a bug only affecting some planets, which is why I hadn't noticed it - I've now corrected it (I think).

As that indicates, there are still quite a lot of bugs to sort out with this, but the basic functionality is working reasonably well and I think it adds a nicely dynamic element to the worlds, which makes them feel that much more believable.

Friday, December 15, 2023

Atmospheres

When I started this project, I didn't think I'd be spending much time simulating air, but here we are. My planets now have atmospheres:





I looked at a number of atmosphere shaders but couldn't find one that worked well with what I already had, so I wrote my own from scratch. As with most of what Undiscovered Worlds does, it aims for superficial believability rather than accuracy, but I think it looks reasonably decent. It doesn't actually calculate Rayleigh scattering and the like, but it pretends that it does. You can adjust atmospheric thickness, colour, specularity, etc. in the appearance settings.

The clouds are formed quite simply:

(1) Several fractal maps with different levels of detail are made and then combined. Then these are converted to the range -1 to +1, and then turned into their absolute values before being inverted. This gives the effect of wiggly lines. Finally, the resulting map is warped. This gives us the fairly large blobs of cloud with some stringy bits that you can see in the images.

(2) Then, another fractal map is made with a much smaller granularity. A map with larger granularity is used to remove large sections of this. This produces the smaller, puffier-looking areas of cloud.

(3) These two cloud maps are combined using yet another fractal, so that they merge into each other in a varying way.

(4) A simple swirl effect is added in places to give the effect of weather systems. Of course we make sure that these swirl in the correct direction, depending on hemisphere and overall planetary rotation direction.

(5) Clouds are removed in areas of low precipitation, to ensure that you don't get great big weather systems over deserts and the like.

Plus I've reduced the effect of the normal map, and made wetlands and large rivers visible (and specular) from space.

As always, it's not perfect, but I think it's looking reasonably decent. I shall probably continue to tinker with the clouds, but for now I'm happy to move on to the next bit, which will be some boring refactoring. I'm using a lot of three-dimensional vectors now, which are slow, resulting in annoyingly long planetary generation times. So I want to rewrite them all as one-dimensional ones to see if that speeds things up.

(Bonus shot: ocean worlds can now look quite dramatic:)