A Matter Of Scale

Growing up I was always a big fan of space, and to some extent, I knew space was big, but it was not until I started building a galaxy that I truly understood just how big space is. It’s truly unfathomably large.

When I set about making Starsim I knew what I wanted from the galaxy, which was for it to be freely and completely navigable in every direction. No borders, no loading screens, just point the ship at a star (or a location between stars) and hit the go button. Basically, I wanted something like Space Engine, but with a fully simulated ship and crew, and lots of interesting things to discover and interact with.

As of this morning, we’re pretty much halfway there with that overall vision, and I just wanted to elaborate on what it is we’ve actually got now.

Part of the challenge of simulating an entire galaxy is the numbers. They get very big, very quickly, and when you consider Unreal Engine works at a unit-scale of 1cm you can imagine that even the ISS orbiting Earth is already 677,100,000cm from the Earth’s origin point (absolute middle). The Moon is 39,116,900,000cm from the Earth’s origin point, which already exceeds the number of digits in a 32bit integer.

So how do we build an entire galaxy? Well, the trick is a shifting of scales. You need to break it all down into bite-sized chunks, and in our case, that’s a unit scale of 1 light year. The galaxy is about 100k lightyears across, and that’s a much smaller number to be dealing with. But, when you look at the cubic lightyears in the galaxy you suddenly reach a figure of 10 Trillion. That’s 100,000 x 100,000 x 1000 = 10 Trillion.

Remember that 32bit integer? Its limit is 2.4 billion, so once again the numbers are too large. Time to subdivide even further, because specifically, we need less than 2.4 billion cubic units in order to give each one a completely unique random seed value. (Random streams in UE5 are limited to 32bit integers as well)

So what if we now group our lightyears into 100ly cubes and call them sectors? Now we have 1,000 x 1,000 x 10 = 10 Million. That’s much better, and we now easily have enough unique integers to give each 100ly sector its own unique seed. But wait, what about seeds for the ~4000 or so stars in each sector?

Well, this is where we have to think outside of the box. There are around 400 billion stars in the galaxy, not to mention all the other things we need to include like rogue planets, black holes, or any other kind of stellar phenomenon. Again, there’s no way they can each have a unique seed. So, what we do is generate some basic star details using the sector’s seed, which we know is universally unique, and generate things such as Spectral Class, Kelvin, Radius, number of planets, etc.

We then give that star (or another object) its own random seed between -2 Billion and +2 Billion for a total of 4 Billion possibilities within the 32bit integer. But with 400 Billion stars doesn’t that mean some will get the same seed? Yes, they will, but…

While we will have multiple star systems with the same seed, they will still be different because the details of the star itself are made with a unique seed, and those details modify the outcome of the planetary generation algorithms. What is an Earthlike in one-star system could be an ice planet in another, even though both systems share the same seed.

In short, the chances of the same random star values being assigned the same seed from a pool of 4 billion are…. astronomical. And with 400 billion star systems to explore, good luck finding two of the sameĀ 

But what about actually getting to those star systems in real-time and being able to explore them? Well, if we go back to that 1cm scale problem then it’s clear we need to start thinking outside of the box again. Literally in this case, because we’re now going to separate each cubic lightyear into around 473,000^3 boxes that are each 20,000,000km across. This represents the absolute limit on how far the player ship can move (keeping that cm value within reason), and exceeding that distance simply puts you in the next box.

Except, a galactic resolution of 20,000,000km isn’t very granular, so how about we subdivide each of those boxes into 1000km cubes, giving us some 9 billion ^3 spatial units to place something within a star system. This means you can target and warp to any location in the entire galaxy down to a resolution of 1000km. It also means no two spawned objects (moons, space stations, derelict ships, etc) can be closer than 1000km to one another.

You can fly perfectly smoothly between two 1000km cubes, but in terms of nav targeting and spawning that’s the resolution, we’re working with. If you multiply 10 Trillion cubic lightyears by 9 billion ^3 you get a number so huge that it breaks Excel

So that’s how we’re doing it. Shifting scales and some out-of-the-box thinking. The net result is we have achieved our goal, allowing players to travel the entire galaxy with complete freedom of movement, and allowing for the ability to spawn in any interesting objects virtually anywhere.

The next goal moving forward with this system is to be able to see the milky way disc and multi-lightyear nebulas moving while you are at warp, to the point where if you fly high enough above the galaxy you’ll be able to literally see the entire milky way out of the window. It’s completely within the realms of possibility, and I’m excited to see where we go with it next!