Planet family

I’m very happy with the results of last log. While there are still some major things I want to change, I think it’s time to move on to make other planet types. There is however one simple thing I want to change before we move on. Right now we have an atmosphere that gradually decreases it’s transparency moving towards the center of the planet. We did however forget to make a small extra gradient outside of the planet. The atmosphere needs to slowly transition into the blackness of space. This is easily done by adding a few extra pixels outside of the planet’s radius and linearly transitioning the transparency. The result is awesome:

ProceduralPlanetNewAtmosphere

Ok, now I’m happy to move on. We have our nice Earthlike planet generator, but the universe does not consist of only Earthlike planets. In fact, there are probably not a whole lot of these things. Most planets are barren rocky worlds or gas giants. So what types do we need to be able to generate? Let’s take a look at Wikipedia’s list of planet types and make a list of the most common and interesting ones.

PlanetTypesTable.jpg

Ok, we need to change our generator so that it can make 8 different types of planet. This should not be too hard as we already have the basic tools to do this. Let’s start at the top and work our way down.

Desert planets

Desert planets are awesome. They have been very popular in science fiction. Think about Tatooine (Star Wars) and Vulcan (Star Trek). To generate them is very easy. We ditch the Whittaker diagram and make the terrain colors purely noise based. These are some results:

Gas giants

We already did Earthlike planets so let’s move on to gas giants. Gas giants are planets similar to Jupiter and Saturn. They are pretty easy to generate. We just take a color gradient and perturb it with noise to generate the colored bands of gas:

Ice giants

Ice giants are very similar to gas giants. The main difference is their colors:

The main problem that I currently have is that they don’t look as spherical as I would like. This is because we don’t use the noise for the 3D effect as with the other planets. I’ll look into the spherification of gas and ice giants at some other time. For now, I’m satisfied.

Ocean planet

Ocean planets are also very simple. They consist of one main water color, a lot of clouds and a thick atmosphere. With some changes in the variables of the desert planet generator, we get these results:

Rocky planets

Rocky planets are planets like mercury and the moon. They consist of different gray tones and are pretty rough. They also have things like craters and mares which I will look into at another time (although using just noise also gets nice results):

 

I’ll skip the icy planets for now as they require the generation of linea, which requires a lot more time than I currently have.

Lava planets

Lava planets are pretty much the same generation process as desert planets, but with a lava like gradient:

Alright! That’s all. I’m very happy with the results of today. I’ll be tweaking and adding to the generators a lot, but the basics are here. Next time we’ll do something different. I want to start taking a look a the generation of solar systems, so that will be fun!

Planet generation

In the last two posts I discussed the potential problems that we will be facing and the tools that we could use to generate our content. The next task is to actually start doing something. Let’s take a look at our list of scale layers from log 1.

ScaleLayerTable

One of the most interesting things from this list is the visual generation of planets, moons and stars. It will also serve as a nice building block to start working on other scale levels. So let’s lay out a plan.

The first task is to determine what visual style we will be working with. I personally like pixel art as it leaves room for your own interpretation. Not only that, pixels are easy and fast to generate. So my planets will probably look like circles filled with big pixels.

The first step is to generate a circle on a texture. This is pretty simple. We just make a double for loop that loops through each pixel of a Texture2D. We determine a radius and we set each pixel outside of the radius to Color.clear.

When a point is inside the radius we get the perlin noise value for that point. We can of course change the looks of the perlin field by changing the seed, octaves, frequency, etc. We then set the pixel color to a point on a color gradient to get the desired color at that height.

This is the result:

Procedural planet

Ok, it looks kinda like a planet, but not really. We are missing a few things. One is climate. There is no difference between the poles and the equator. Desserts should not be placed around mountains. This is just a color gradient on a heightmap.

Another thing that bothers me is that the planet still looks flat. Sure it is circle shaped, but not really spherical. We could of course render a real 3D sphere, but that is much more difficult to work with. What I want is that the pixels become more compact as we approach the edge of the circle.

Procedural planet

vs

Earth

Biomes require more work, so let’s focus on the spherification of our 2d texture. This requires a bit of math (something that I’m terrible at). What we need is the equation for a circle:

x^2+y^2=r^2

CircleGraph

This equation uses an x and y position to calculate the radius. But what we want to get is the y point at a certain x point with a given radius. Why? Well, our current planet is circular from the side view. If we could make it circular around the equator as well, we should get our desired ‘depth’. So what I want to do is to use the circle equation to get a z coördiate, which we can put in the perlin noise to get a 3D planet, but displayed in 2D. The first step is to change the equation, so that it gives us the y value when we supply the x and radius.

With some crazy math magic (which I only half understand), the equation becomes:

CircleEquation

So now we can loop from the center of the planet to the edge, and get the ‘height’ at that point. Let’s add this equation to the noise function and see what happens:

ProceduralPlanetSphere.jpg

Now we have a 2D planet that looks spherical, but still keeps the 2D pixel look. I’m pretty happy with the result, and I think we can move on to take a look at climate generation.

Let’s take a look at what climate really is. Climate is the long term condition of air temperature and rainfall. Many people confuse weather with climate. The big difference is time. Weather is the condition of the air at this exact time. You speak of weather when it is raining, or when this was a particularly hot week. Climate is the average temperature and rainfall over a period of 30 years. So a week of increased temperature has pretty much no effect on the climate.

 

So climate (for all intents and purposes) consists of the average temperature and rainfall. All we need to do to generate climate on our planet, we need to know the average temperature and rainfall at a point. How do we determine where to place temperature and rainfall? Let’s look at our own planet Earth.

The transition of temperature on Earth is pretty simple. The temperature is low at both poles and hot at the equator. If we create a gradient like this, TemperatureGradient.jpg  and add some noise, we basically have our temperature map:

ProceduralPlanetTemperature

Now for rainfall. Rainfall does not have such an uniform gradient as temperature has. It is more like waves: RainfallGradient.jpg

This is because of something called atmospheric circulation. If we combine the rainfall gradient with some noise, we get this map:

RainfallMap.jpg

Now we use a Whittaker diagram to get the biome that corresponds to the temperature and rainfall on a pixel. The Whittaker diagram on wikipedia uses values for rainfall and temperature that are different to ours. We work with a maximum and minimum between 0 and 1. So we need to create a square Whittaker Diagram of colors for biomes that uses values between 0 and 1:

WhittakerDiagram

Using temperature as input on the x axis and rainfall on the y axis, we can get the corresponding color for the biome. This is a placeholder texture as I want to take some more time later making the colors look more realistic. Using the input of temperature and rainfall we get this new map:

ProceduralPlanetBiome.jpg

Ok, this is a nice result so far, but we are still missing some important visuals. When we look at the image of planet Earth, we see two important things: clouds and the atmosphere. Atmosphere is simple. We place a second texture on top of our planet that has a circular gradient outwards. The gradient is not linear however, the visual density increases with the curve of the planet. To get the desired transparency, we can use the circle equation again, which gives us this result:

ProceduralPlanetAtmosphere

It looks sort of ok, but I think the denser part of the atmosphere should be placed much closer to the edges. So I will switch the circle equation to an exponential function.

ProceduralPlanetAtmosphere2

That seems better. Now we need clouds. Clouds will be very simple. I’ll be using a fractal noise generator that makes something called billow noise. Billow noise looks like puffy clouds, exactly what we need.

ProceduralPlanetClouds.jpg

Looks pretty solid. So that’s it, I can’t think of anything else that our generator needs. I’ll probably tweak a lot on the generator. The result is pretty nice, but I want to take another look at the colors later.

Bonus image: Crazy alien planetProceduralPlanetAlien

 

The universe is a noisy place.

In the last devlog I made, I talked about the possible technological problems that we will be facing during this project. With that out of the way, we can think about how we will fill our huge universe with interesting objects. Manually designing and placing them is obviously out of the question. I don’t have that much time. (if I could place one star per second, it would take 3^13 years to fill the universe). So we need to use some system that (semi) randomly generates these objects. This is called procedural generation.

Rulebook

Procedural generation basically generates data according to a series of rules that we make. For example:

We want to generate a star. How? Well, let’s take a look at the properties of a star that are important to our game. One thing is the temperature on planets. The average temperature on the earth is about 14.6 ℃ (58.3 F). The temperature is mainly determined by the amount of light that the sun throws towards us, and the amount of light that the sun produces is determined by its mass. So let’s say that its mass is 1.5 times the normal mass. With some equations we can find online we can calculate that the brightness of the star would be 3.4 times more than normal, and the average temperature on the earth would then be 72.85 ℃ (163.13 F). Pretty toasty.

So we see that the first ‘rule’ we need to determine the temperature of the planet is the star’s mass. We can then calculate all other properties using formulas we can find online. So when we want a random star, we just create a random number for it’s mass, and we let loose the equations. Pretty simple.

Noise

Equations are nice for numbers, but what about the shape and look of things? How do we randomly generate interesting surface features like hills, mountains and rivers on a planet? We use something called fractal noise. My favourite flavour is perlin noise, created by Ken Perlin.

PerlinNoise1

This is Perlin noise. It looks like clouds, so we could use it to generate clouds, and we probably will, but it can be used for much more. Perlin noise is based on a frequency, it you increase the frequency, the clouds will be closer together.

PerlinNoise1
Frequency: 0.01
PerlinNoise2
Frequency 0.02
PerlinNoise3
Frequency 0.04

So if we increase the frequency, we can influence the output. There is another thing we can do to change the looks. Right now the noise looks very smooth. We might not want smooth noise. To add more detail to the noise we can ‘layer’ one frequency on top of another, and merge them together. The amount of times you do this are the octaves of the noise.

PerlinNoise1
Octaves: 1
PerlinNoise4
Octaves: 2
PerlinNoise5
Octaves: 3

Now this changes things drastically. We can use this noise to generate many things, most important: landscape. The images above are in a grayscale gradient, much like a heightmap. What would happen if we use a color gradient for the output?

PerlinNoise6
Octaves: 1 with color gradient
PerlinNoise7
Octaves: 3 with color gradient
PerlinNoise8
Octaves 6 with color gradient

There are many more types of noise we can use for other stuff.This could be the start of our planet’s surface generator. We can see continents, oceans and mountains. Next we can add some temperature and rainfall data and place corresponding biomes on the map.

Armed with the tools of random numbers and noise generators, we can create most interesting stuff in the universe. Stars, planets, solar systems, galaxies, countries, cultures, you call it.

A 2D space engine? How?

A 2D space engine that has all things the real 3D universe has to offer (but displayed in 2D). This is an idea that started a few years ago. I started programming with Unity3D and quickly discovered the possibilities of procedural generation. I had the pretty radical idea that it should be possible to generate everything there is in the universe and build a game around it. While it is theoretically possible to generate such an universe, the current computer technology would not be able to deal with this amount of data. But there are games that work around these kinds of problems. Think about Kerbal Space Program and the Elite games. How do they solve these problems? Let’s first take a look at the problems that we’ll be facing.

Problems of scale

There are two main problems that I will be dealing with in this project. The first is the ridiculously huge amount of data that needs to be generated. The second problem are the huge distances between objects. In short, space is big and there’s a lot in it.

Problem of data

The huge amount of data is probably the easiest to work around. When the player is approaching the spaceport that orbits around a planet, we don’t need to generate all the stars in it’s galaxy. We don’t need to generate the other planets in the system. We don’t need to generate all the people that live in the cities on the surface of the planet. We only need to generate what the player can see: a model for the spacecraft, a model for the spaceport, and a planet. So that is three things versus something on the order of 10^24 (a 1 with 24 zeros, rough estimation for the amount of planets in the universe). It won’t be too difficult to create a system that generates things based on the current situation of the player.

Solving the problem of data

So we need a system that generates only what we need at a certain situation. This is done by making a list of rules for every possible situation. The game will then detect the situation of the player, and generate the objects based on the rules in that list. It will probably look something like this:

SituationTable

This would work pretty well as an initial setup. There is still a problem when viewing a map of the universe, but we’ll think about that sometime later. We will off course limit the size of the game to 2D, so that makes things easier.

Problem of distance

The problem of distance is a bit more difficult. This is more of a technical problem. And the problem houses within Unity3D (ok, I’m not hating on Unity, pretty much all game engines have this problem). Distances in unity are given in units. A unit is pretty much what you say it is. For example, I can say that 1 unit is 1 meter. This would mean that a spaceship of 100 meters long is 100 units. Ok that seems reasonable, but what if our spaceship is orbiting the planet at a height of 400 km (roughly the height that the ISS orbits). If we say that the player is at coördinates (0,0,0), the surface of the planet would be at (0,400 000, 0). Ok, 400 000 is a number that I can understand, no problem. Let’s punch that number into unity.

FloatingPointError

A warning. Unity recommends us to bring the range of coördinates within 100 000 units. Why? Let’s take a look.

Solving the problem of distance

So what is going on here. Unity is complaining about large numbers. Let’s take a look at how numbers are stored in computer memory.

Unity uses floats to store coordinates. Floats are numbers that can have a decimal point (1.75 or -9872.22). But there is a limit to how large floating point number can be. I don’t know fundamentally how floating point numbers work, but I’ll give an example of what I think is going on. Let’s say that our number can occupy 10 ‘memory slots’. If we add a decimal at the 9th slot, we can make numbers like 826572918.5

Ok neat. But 1 decimal is not really precise. When our spaceship is moving, it will not travel in steps of 0.1 meters. That would create very shakey and imprecise movement. Let’s say that we need an accuracy of at least 4 decimal points to calculate our movement more precise. That means that we will have only 6 more ‘slots’ for the rest of the number.

So what we see here is that accuracy drops with larger numbers. This is a huge problem, because we want to use large numbers, but also accurate position calculation. So what is the solution?

It is called a ‘layered coordinate system’. This is the same concept that Kerbal Space Program (also made in Unity) used to display their solar system. The idea of a layered coordinate system is that you use different units of measurement in different layers. For example: when we are rendering the scene of a city, we need our meter units to accurately place buildings, npc’s, trees, etc. But we also want to see that moon that is orbiting the planet. That moon might be 384 million meters away.

But what if we say that the coordinate layer of the moon is different than the coordinate layer of the city? Then we could say that 1 unit is not 1 meter, but 1 000 000 meters. Now the moon is 384 units away. Ok, great, but the moon is now physically closer to the planet than it should be. Unity still thinks that it is 384 units away, but we can solve that by changing the scale of the moon. We increased the scale of units by a factor of one million, now we need to say that the moon’s size is decreased by a factor of one million. The diameter of the moon is 3 474 000 meters. But when we apply our scale factor, it will be 3.5 units wide. That is easy for unity to calculate.

So we use many layers of different scales. For each object in a layer, we apply the scale factor to the position, size and other properties that are influenced by this (orbital speed for example).

Again this is the solution for a 3D game, so we will only deal with a small amount of these problems.

The scales in our game

Some of you might have noticed that we can resolve both out problems with the same solution. We use the different layers to deal with distances, and we use layers that the player is currently in as our situation. Great! So what layers do we need? Let’s start at our smallest layer: 1 unit = 1 meter.

Let’s take a look at the Wikipedia page on orders of magnitude.

In the first table we see increments of 4 orders of magnitude with each step. So that means that the next layer would be at 1000 meters. That is a little bit low as we have more room in out limits, but it will be easy to work with. As we can see in the table on Wikipedia, the maximum value is a ridiculously huge number: ten to the power of 10 to the power of 10 to the power of 122. That’s a bit much, so I’ll set my maximum distance to 10^24 meters. That is roughly the size of the Virgo supercluster or about 100 million light years. There are about 5000 interesting galaxies in that area and roughly 200 trillion stars. I think that is enough content for our game. We might add an extra 3 orders of magnitude when I’m bored and want to add the rest of the universe.

So our layer table looks like this:

ScaleLayerTable

So we’ll end up with 8 layers. That seems manageable.

How will these layers work in our 2D game. My game will be viewed top down for most situations, so we don’t need to be able to ‘look’ very far like you need to in a 3D game. However I want to be able to zoom out and transition from small scale to larger scale.

This sums up the main structure of our space engine. I’ll take a look at the generation of the objects that will populate my engine in the next log.

Game design and development