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:)


Sunday, November 26, 2023

Shiny!

There's not been much activity here recently, but things have been moving behind the scenes. I've mostly been trying to work out how to improve the visuals for my planets. I was just using OpenGL to display them, and I wrote last time about wondering whether to change to a less low-level approach that might make it easier to get a few nice visual effects in. (I was particularly missing the fake 3D effect of my old maps.) After a lot of time alternating between digging deeper into OpenGL and trying alternatives, I decided to use raylib, which is not an engine so much as a library that keeps things pretty low-level, but without quite as much fuss as doing everything in OpenGL directly. Also it's easy to use ImGui with it, and I wasn't going to redo all the GUI at this stage.

There's still quite a lot of getting one's hands dirty with this. I've spent a lot of time tinkering with shaders, and have managed to generate some fairly simple effects, but I'm quite pleased with them:

Getting the normal map to work properly was very fiddly. For some reason I don't understand (a glitch in my cubesphere object, or a glitch in my shader?) the shadows on the top and bottom faces of the cubesphere vary incorrectly across the faces, even when the normal map is definitely correct. So I had to mess about with my normal map creating routine to vary them in the opposite way, to counteract this effect. It's still not perfect, but it looks mostly OK, so I'm sticking with it for now. It's certainly nice to see shading on my mountains again (even though, at this scale, it's probably too exaggerated).

Next I need to think about how to improve my shader - ideally by adding some basic atmospheric effects, as well as clouds, if possible. And then I'll need to think about how to integrate the regional map level into this system, which is where things will get tricky.

Tuesday, September 12, 2023

Another decision point

Time (at last) for a new update!

I have, more or less, managed to convert all of my existing terrain and climate routines to work with spherical planets. This has been quite fiddly to do. Some could be converted fairly straightforwardly, while others could not. In some cases I had to rewrite them from scratch, and in extreme cases I had to simply alter them to work with a giant 2D map which subsequently gets wrapped onto the sphere. In some cases I found that the rewritten versions were better than the original - e.g. my continent-generating routines now seem to throw up more varied terrain more often, including archipelagos, meaning that I don't need to use the Aegean-creating function.

I was particularly held up by a subtle but nasty bug in my routines for moving from one point on the sphere to the next, which caused inaccuracies when moving from one face to the next. Much of my time was spent writing workarounds to deal with the effects of this bug until I finally found it, after which I had to go through and remove some of those workarounds.

But it's done! Mostly. All four of the planetary types (small continents, large continents, oceanic, and non-tectonic) can now be in spherical form, and in all three planet sizes too. Most features such as mountains, dunes, lakes, wetlands, craters, etc. are present, as are the variable climates (including exotic climates). There are still some issues. Artefacts occasionally appear at the edges of faces, and occasionally the whole thing crashes. So there's still some work to be done smoothing it all.

Here's a typical continental world, showing some of these features:


Here are a couple of non-tectonic worlds that I thought looked interesting:




Some new terrain features are possible now. For example, rarely, ocean ridges on small worlds can create planet-wrapping archipelagos and islands:


This was unplanned, but I like the effect, so I've left it in as an occasional possibility.

And you can of course view things like rivers on the globe:


- and climate types:


So now there are two problems I need to consider.

First, what engine should I use to display all of this? At the moment I'm just using OpenGL directly. This is fine for displaying simple objects such as the facets of my globe, but doing more elaborate effects is probably beyond my abilities. So far I've not been bothering about this as I wanted to work out whether I could create the terrain etc. of the planets first, and worry about how to display them later. But obviously with this method I can't do things like apply shadows, which means that they don't look as nice as my 2D maps that have the faux shading effect. So I'm wondering whether to use an existing engine such as Irrlicht to render the globe, which might allow me to do more. But then of course I'd have to learn how to do that...

Second, what about the regional maps? As things stand, I haven't implemented them at all yet in this new version. The actual generation of them shouldn't be too tricky. (I know I will regret typing that! But at the moment I think it should be fairly straightforward to convert the existing regional map creation routines to work with the spheres.) The problem is how to display them. One option is to keep the system of a zoomed-in mode, where the region is displayed as a 2D map, just as it is now. That would be very straightforward. But consider again what each region represents:


Each tile here is a region (supposing this is an Earth-sized world). Now suppose we zoom in on one in the middle of the "face" that is facing us. All is fine - it can be displayed in the zoomed-in screen, and we can scroll around to north, south, east, and west. But suppose we keep going north and find ourselves on the "face" that's on the top of the cubesphere. Scrolling around here won't be taking us north, south, east, and west any more, at least not in any consistent way. Suppose we now scroll to the right and go down the "face" to the right of this image. When we started on the first face, the top of the map was pointing to the north. But now it's pointing east. Things get even worse if we try to navigate around one of the points where three "faces" meet.

All of this comes from the fact that the world isn't really a sphere at all, but a cube, and if we display the regional map in 2D form it's going to be very hard to conceal this fact.

So the alternative is not to do it that way at all. Instead, we could allow the user to zoom gradually in on the globe, generating the regional maps as they do so, and then display those maps directly on the globe itself. So as you zoom in on the map you would see the regional-level details popping in once it's close enough.

There are two problems with this. The first is that it's hard! We'd have to be able to generate regional terrain on the fly as the user is moving around the globe, and keep track of which regions have been generated, which ones need to be generated, and be able to paste them onto the right bit of the globe. All of this is theoretically possible but could be a nightmare to implement.

The second problem is that some tiles would get distorted. Look again at the image above, and in particular the regions at the corners. We get away with the distortion at these points at global scale, but I worry that at regional scale it would look pretty bad. Mountains and rivers, in particular, would look unnaturally stretched.

So I'm not sure what to do about this. The next job is therefore probably to convert the regional map generating parts of the program and try pasting the generated maps onto the globe to see how they look.

Wednesday, June 28, 2023

The blue marble

I've not had much of a chance to post any updates for a while. This is partly because I've been very preoccupied with real-life distractions (finishing the first draft of a book 😱) and partly because the process of translating everything into spherical form is pretty time-consuming.

Much of the difficulty comes from having to deal with multiple coordinate systems at once. The cube-sphere, as described in my last post, is really good for creating terrain that looks reasonably good from all angles, without the distortions you get from just wrapping a rectangle directly onto a sphere. From any given point on the cube-sphere you can easily move to the neighbouring points in a grid fashion, just like on a 2D plane (except at the corners of the faces, where it gets tricky). However, if you want to move due east or west, or north or south, it's much more complicated, because the grid doesn't line up with those directions unless you're right on the equator. To work those out you need to know the longitude and latitude of the points, and converting from cube-sphere coordinates to longitude and latitude (and back) is both fiddly and resource-intensive. And being able to specify directions of this kind is essential for the climate simulation.

Still, I've made some progress. I've converted most of the standard continental terrain generation to the spherical form, and made a good start on the climate model. Temperature and basic rainfall are in place, as well as wind directions and sea ice. Here are some pictures - they are all of the same world, which hopefully gives a sense of how the globe looks from different angles:




Here's the south pole, so you can see it's possible to have polar continents without distortion:


And here are the wind bands (red: westerly; cyan: easterly), which aren't very realistic, but I'm not going to try to change them:


There's a still a lot to do. I've been having a lot of difficulty getting the mountain generation methods to work well with the globe - in fact I've had to create an entirely new way of doing the mountains along continental edges, which is based on the functions I originally created to import user-generated mountain maps. But there's more work to be done with them (the world shown here is one of the most mountainous I've been able to generate, and it still looks very flat). Then I need to add the monsoon routines, before getting to grips with rivers and lakes, which is never much fun. But I think I've reached the point where it looks like converting this whole thing to spherical worlds can actually work, so I'm hoping the final results will be worth the effort...

Saturday, April 1, 2023

Cubular balls

After the last release version of Undiscovered Worlds I'm more or less at the point I was nearly four years ago, when I got as far as I could with the original version of this project in AGK. Back then I wondered which of these three things to do next:

(1) Create a new level of detail, so one could zoom in on the regional maps and expand them.
(2) Start populating worlds with procedurally generated life forms.
(3) Rewrite the entire thing in a more suitable language.

I went for option (3), and the current state of UW is the result. It's much better than what I had then - faster, fewer errors, more options and variety, and much more detail and realism (within reason). So what next?

Options (1) and (2) remain on the to-do list, and I was initially going to get cracking with (1). This would add "local" maps, which would have the same relation to the regional map that the regional map does to the world map. But before doing that I thought I'd try a bit of more fundamental experimenting with the program.

One obvious limitation of UW as it stands is that it deals only with flat maps. I wrote right back at the start that creating spherical worlds is theoretically possible, but I wasn't going to try it as it's too difficult. But I've always wished I could have done it, and this limitation is more apparent now that worlds with different climates are possible. That means that there's no guarantee that any given world will have ice caps at the northern and southern edges of the map, which in turn makes it harder to hand-wave away the terrible warping that happens if you try to wrap one of these rectangular world maps onto a sphere.

So I thought, having come this far, I might as well at least try to see whether I could rewrite the program to work with spherical worlds. If it doesn't work then I can just give it up and continue with the flat maps as before, but it might be interesting to see what can be done.

So after a fair bit of tinkering, and wrestling with the horrors of OpenGL textures, I have this:


This is my existing diamond-square algorithm, which forms the basis for a lot of the global generation, but rewritten to map onto a sphere. This wasn't easy, but it works!

The basic idea is to represent the world as a cube. Each of the six faces of the cube has its own terrain map. When the cube is displayed, we warp each face to form a sphere shape:


This works because each face of the cube is not a single plane object but a grid of 16*16 of them. We warp the cube by taking each vertex of each plane object and transforming them using the extremely useful formulae found here. Here's what it looks like if we show all the sub-faces:


So our sphere is actually a polyhedron made up of 1,536 squares, which are distorted to varying degrees. As you can see, this projection keeps all of the subfaces roughly the same size as each other, but distorts the shapes towards the edges of the faces and especially at the corners. An additional irregularity is that where most of the squares have eight neighbours (including the diagonals), the ones at the corners have only seven.

The visualisation is useful because each of those squares also corresponds to a single regional map. Exactly how the regional map will work with this remains somewhat unclear, particularly when it comes to navigating round the corners, but I'll cross that bridge if I come to it.

In any case, the distortion involving in warping the cube into a sphere is much less than you get if you try to wrap a rectangle onto a sphere. In the latter case there are two points of distortion - the north and south poles - whereas with the cube there are eight - the corners. That shares out the distortion more evenly so that it is much harder to see.

The next job is to see if I can adapt the rest of my global terrain (and climate!) generation algorithms to the spherical maps. I'm fairly sure it should be theoretically possible, but that doesn't mean it's practical to do, so we shall see... If not, back to the flat maps!

Friday, March 10, 2023

Update: version 1.0 now downloadable

The updated version of Undiscovered Worlds is now downloadable on the first page. I've also updated the instructions for use there, and the screenshots. Since the previous version was rather unpolished compared to this one, I'm retroactively numbering it 0.x and calling the new one 1.0!

Note that saved worlds and settings from previous versions aren't compatible with this one.

The new version has all the features I've written about since the original upload, plus a few that I haven't. Here's a summary:

UI and presentation

  • Proper installer application
  • New app icon (courtesy of u/Iron-Phoenix2307)
  • Nicer font (Roboto)
  • Clearer organisation of information
  • Automatic update notifications

World generation

  • Three sizes of worlds now possible
  • New terrain types: non-tectonic and ocean worlds
  • Greater variety of tectonic terrain
  • New features: craters, mud flats, beaches, mangroves
  • Much larger sandy deserts
  • Variable planetary information: orbital eccentricity and obliquity, gravity, etc
  • More robust, detailed, and flexible climate modelling, allowing for exotic climates

Custom worlds

  • In addition to importing maps, custom-generated ones are now possible with user-defined settings
  • Ability to specify all planetary variables, including extreme settings
And of course various bugs have been eliminated, and many exciting new ones added.

The source code has all been updated too, so everyone is welcome to poke around in there too.