First the sphere is divided into 6 regions.

Then we just do a flat projection on each of those faces. So how does it look with a texture?

Looks good!

Well, at least all the lines connect…

So we want this to be a square, not a triangle. Also, the border of each face should align with the texture borders. Right now they start overlapping at the edges.

So how do we solve this? Remember at the beginning I said we put the sphere inside a cube. It turns out that it works much better if we put the cube inside the sphere. This does require some math though.

Let’s use the subscripts c and s for cube and sphere respectively

First, normalize all the coordinates

So how do we solve this? Remember at the beginning I said we put the sphere inside a cube. It turns out that it works much better if we put the cube inside the sphere. This does require some math though.

Let’s use the subscripts c and s for cube and sphere respectively

First, normalize all the coordinates

Code Editor

Then divide by the max value. This is the part that puts the cube inside the sphere.

Now each coordinate goes from -1 to 1 but this would cause the texture to repeat one. So we remap the range to 0 to 1.

Finally we choose the appropriate coordinates for each face.

Code Editor

Here’s how this looks

So now all the edges line up and things look much better. But it’s easy to see that the squares at the center of each face are larger than those near the corners. To solve this we need a better mapping. This post goes into the math of this next mapping, but here’s the equations.

\[ x_s = x_c \sqrt{1 - \frac{y_c^2}{2} - \frac{z_c^2}{2} +\frac{y_c^2 z_c^2}{3}} \]

\[ y_s = y_c \sqrt{1 - \frac{x_c^2}{2} - \frac{z_c^2}{2} +\frac{x_c^2 z_c^2}{3}} \]

\[ z_s = z_c \sqrt{1 - \frac{x_c^2}{2} - \frac{y_c^2}{2} +\frac{x_c^2 y_c^2}{3}} \]

Since we’re already splitting into 6 faces we can simplify by setting z_c = 1

In this case we break up the coordinates by face before doing the math

\[ x_s = x_c \sqrt{1 - \frac{y_c^2}{2} - \frac{1}{2} +\frac{y_c^2 }{3}} \]

\[ y_s = y_c \sqrt{1 - \frac{x_c^2}{2} - \frac{1}{2} +\frac{x_c^2}{3}} \]

\[ z_s = \sqrt{1 - \frac{x_c^2}{2} - \frac{y_c^2}{2} +\frac{x_c^2y_c^2}{3}} \]

\[ x_s = x_c \sqrt{ \frac{1}{2} - \frac{y_c^2}{6}} \]

\[ y_s = y_c \sqrt{ \frac{1}{2} - \frac{x_c^2}{6}} \]

\[ z_s = \sqrt{1 - \frac{x_c^2}{2} - \frac{y_c^2}{2} +\frac{x_c^2y_c^2}{3}} \]

Solving for x_c and y_c so we only need 2 equations.

\[ x_s = x_c \sqrt{ \frac{1}{2} - \frac{y_c^2}{6}} \]

\[ y_s = y_c \sqrt{ \frac{1}{2} - \frac{x_c^2}{6}} \]

Now solve for x_c and y_c

https://www.wolframalpha.com/input/?i=a+%3D+x+*+sqrt(1%2F2+-+y%5E2%2F2++%2B+y%5E2+%2F3),++b+%3D+y+*+sqrt(1%2F2+-+x%5E2%2F2+%2B+x%5E2+%2F3),+solve+for+x,y

Rather complicated, but some manual simplifying gives this.

\[ x_s = x_c \sqrt{1 - \frac{y_c^2}{2} - \frac{z_c^2}{2} +\frac{y_c^2 z_c^2}{3}} \]

\[ y_s = y_c \sqrt{1 - \frac{x_c^2}{2} - \frac{z_c^2}{2} +\frac{x_c^2 z_c^2}{3}} \]

\[ z_s = z_c \sqrt{1 - \frac{x_c^2}{2} - \frac{y_c^2}{2} +\frac{x_c^2 y_c^2}{3}} \]

Since we’re already splitting into 6 faces we can simplify by setting z_c = 1

In this case we break up the coordinates by face before doing the math

\[ x_s = x_c \sqrt{1 - \frac{y_c^2}{2} - \frac{1}{2} +\frac{y_c^2 }{3}} \]

\[ y_s = y_c \sqrt{1 - \frac{x_c^2}{2} - \frac{1}{2} +\frac{x_c^2}{3}} \]

\[ z_s = \sqrt{1 - \frac{x_c^2}{2} - \frac{y_c^2}{2} +\frac{x_c^2y_c^2}{3}} \]

\[ x_s = x_c \sqrt{ \frac{1}{2} - \frac{y_c^2}{6}} \]

\[ y_s = y_c \sqrt{ \frac{1}{2} - \frac{x_c^2}{6}} \]

\[ z_s = \sqrt{1 - \frac{x_c^2}{2} - \frac{y_c^2}{2} +\frac{x_c^2y_c^2}{3}} \]

Solving for x_c and y_c so we only need 2 equations.

\[ x_s = x_c \sqrt{ \frac{1}{2} - \frac{y_c^2}{6}} \]

\[ y_s = y_c \sqrt{ \frac{1}{2} - \frac{x_c^2}{6}} \]

Now solve for x_c and y_c

https://www.wolframalpha.com/input/?i=a+%3D+x+*+sqrt(1%2F2+-+y%5E2%2F2++%2B+y%5E2+%2F3),++b+%3D+y+*+sqrt(1%2F2+-+x%5E2%2F2+%2B+x%5E2+%2F3),+solve+for+x,y

Rather complicated, but some manual simplifying gives this.

After x_c finding y_c is easy.

As before x_c and y_c are currently from -1 to 1, so rescale to 0 to 1

There’s still some distortion, especially near the corners. But overall each square is about the same size.

The final thing is giving each hex its own texture. Fortunately, this part is simple. For each type of terrain we want we need a different texture. This texture is then applied just like the test pattern above.

The final thing is giving each hex its own texture. Fortunately, this part is simple. For each type of terrain we want we need a different texture. This texture is then applied just like the test pattern above.

Finally, just like with cell colors, each cell chooses a texture and then the texture is blended between cells.

]]>Is there a better way to do this? Well we already store the position of each vertex, can we use that? Yes, to change the height of a vertex we can just normalize its position vector, multiply that by the new height, and add it back to the original vector. Doing this we can change the height of a vertex 5 times faster than by using spherical coordinates.

Now that that’s out of the way lest implement it. Let’s look at what we currently have.

First we’ll just change the height of the cell centers. I’m using a map of Earth to decide the height of each cell.

Doesn’t look that great but it’s starting to work. Thankfully all the work we did to get color to blend will also let our height blend. First the bridges.

Then the corners.

That looks like a planet! But it is a little boring, what if we changed those flat slopes to terraces (look here for the math involved)?

Better, but the flat land looks a bit strange. And the tall cells don’t look great either. Lets only add a terrace if the neighboring cells have a small height difference.

That’s better, gives some terrain variation but doesn’t look too strange. Just need to fill in the corners

Looks pretty good, but it would look even better in color!

Now it looks like a planet. Next we’ll try to add some textures.

]]>This looks nice, but to do anything more we first need to look at how all this works. When we are constructing a mesh really we're just sending a bunch of arrays to the graphics card. The two most important are the positions of the vertices and how they are connected. This is what we did last time. It gives a 3d object that we can work with. But if you want to give the object texture or color you need to also send that data to the graphics card. Texture can get complicated so we'll deal with that later. But color is simple, we can just give each vertex its own color. If we want each cell to have its own color then all the vertices in that cell must have the same color. This means that we can't share vertices on the edge of cells. Thankfully we can afford to have those extra vertices.

So how do we construct each cell? Well, we know the position of the cell's center and corners. But we can't just tell the graphics card to draw a hexagon. See graphics cards aren't actually that smart, for our purposes they're really only good at drawing triangles. So we need to break down our cell into triangles. Easy enough, just make a triangle between the cell center and one of it's edges. Then repeat this for each edge.

So how do we construct each cell? Well, we know the position of the cell's center and corners. But we can't just tell the graphics card to draw a hexagon. See graphics cards aren't actually that smart, for our purposes they're really only good at drawing triangles. So we need to break down our cell into triangles. Easy enough, just make a triangle between the cell center and one of it's edges. Then repeat this for each edge.

Well this looks nice, and it works well. But remember, we eventually want to use this color to represent different types of terrain. More often than not different types of terrain don't have hard boarders between them. So we want to smoothly blend the terrain color between cells. But we still want each cell to have a defined color. We'll do this by scaling down the size of each cell, in this case each cell is 70% of it's original size. This gives each cell a smaller solid region in it's center.

Now it's time to connect the cells. We'll add a rectangle (created from two triangles) to bridge between our cell and it's neighbor. It will reach halfway to the neighboring cell. When we add the color to this rectangle the two vertices near the cell are the same color as the cell. But the two that are far away are the average of the cell's color and the cell's neighbor's color. If we do this for every cell then most of the work is done.

Now there's only a couple triangles left to fill before the color blends nicely. Unfortunately we can't just draw simple triangles to fill the holes. There are two reasons for this. First, when we give the cells different heights later we'll need a more complicated solution. Second, this also lets us make the sphere look smoother. Instead, for each cell corner we'll draw two triangles per cell. The first will connect the cell corner and the two nearby bridge corners. The second will connect the two bridge corners and the center of the hole. We color them similarly to how we did before.

Now we have a nicely colored sphere. We can adjust the amount of blending to whatever we want and it will still look nice. The next thing to do is to give different heights to the cells. But that's a job for another time.

]]>Remember that the other map decision was to use a hexagonal grid. So we just need to cover the surface of a sphere with hexagons.

So map projections, there’s a lot of them, and they all do the same thing, and none are perfect… But why do I care? Well, this is a game about terraforming planets so there needs to be some way to show that planet to the player. In my first post you can see the initial version of this. The planet is displayed as a flat map so I need to use some projection. But this has problems, it distorts the amount of area at each latitude, you can’t go over the poles, and I think it looks bad. The answer to all of this is just make the planet spherical instead of flat, essentially use a globe.

So how to do that? Well, it turns out that if I want to keep the hex grid on the surface it’s

As it turns out that's impossible. Thankfully there is a simple way around this problem, just add 12 pentagons to our hexagons. This is called a Goldberg polyhedron. Now making it!

The first step is to construct an icosahedron. We do this by first defining the locations of all the vertices.

Code Editor

Then connect the vertices into faces. Each line defines a face using the indices of the vertices in the vertex list.

If we tell Unity to draw this we get a nice icosahedron.

Still needs work to become a sphere. So we subdivide each edge and make new faces:

Now there are more vertices but it’s still flat. To fix this we take the new vertices and push them out a bit:

That’s better, let’s subdivide it more:

6 times!

So now we have a nice sphere, but as you've probably noticed there still aren't any hexagons. Well we’re not quite there yet. First we need to break down the sphere into smaller chunks. But why? Unity has a limit to the number of vertices in a mesh. We’re not hitting that yet but as we make the terrain more complicated we might. The easiest way is to use each of the original 20 faces of our icosahedron as a chunk. Giving each chunk a color gives us a nice a beach ball.

Now it's finally time for hexagons. Each vertex of the sphere gets replaced by a hexagon except the 12 original vertices. Those are our pentagons.

Now we finally have the basis for our map. We'll make it look more interesting next time.

]]>Not quite right is it. Although the Sun does provide that much heat it only provides that heat to the side of the Earth facing the Sun. Averaging over the surface of the Earth give a value of 1.361/4 = 0.340 kilowatts per square meter. Plugging this number in gives \(\sqrt[4]{\frac{0.340{kw} m^{-2}}{4 \sigma}}= T = 278.3 K = 41.2^oF\) A much more reasonable answer, although the actual number is closer to \(58.3^oF\).

To get the temperature up those last 17°F we need to look at the greenhouse effect. Thankfully there’s a simple model for this, the idealized greenhouse model. Now the average temperature is given by \(T = \sqrt[4]{\frac{Q}{4 \sigma}} \sqrt[4] {\frac{1}{1-\frac{\epsilon}{2}}} \) . It turns out that \( \epsilon = 0.25\) finally gives us the right answer. Now what is \( \epsilon \) and how do we find it ? Basically, \( \epsilon \) is the factor of thermal radiation reflected by the atmosphere. Unfortunately there isn’t a nice equation, but we can cheat. We know that \( \epsilon \) is related to the amount of greenhouse gasses. We also know the temperatures and atmospheres of Earth, Venus, and Mars. Now we can construct an exponential relating \( \epsilon \) and atmospheric composition. This gives \( \epsilon = 1.92e^{-2.79{P_{GHG}}} \) where \(P_{GHG}\) is the partial pressure of greenhouse gasses in atm. Using these equations we find that to raise the Martian temperature to Earth levels the atmosphere needs to have 0.38 atm of greenhouse gasses.

This is great and all but we can’t just assume that the entire planet is at the average temperature. It should be colder near the poles and warmer at the equator. To do this we can multiply the incoming flux by the cosine of latitude. Because planets are spherical the closer you get to the poles the lower the Sun is and less light hits the ground per area. At the poles the Sun is directly overhead so there is much more light per area. Now our equation looks like this: \(T = \sqrt[4]{\frac{Q Cos(\theta_{lat}) }{4 \sigma}} \sqrt[4] {\frac{1}{1-\frac{\epsilon}{2}}} \). But wait, if we just add a cosine that means the equator is only at the average temperature. So we need to stop averaging over latitude. Fortunately this is as simple as swapping out that 4 for a 3.4 (really mostly to get the equator temperature right. Game dev, not climate science!) \(T = \sqrt[4]{\frac{Q Cos(\theta_{lat}) }{3.4 \sigma}} \sqrt[4] {\frac{1}{1-\frac{\epsilon}{2}}} \). Now, for Earth, the average temperature on the equator becomes 80°F and the average temperature at the poles becomes 0 K or -459.67°F. Not quite right, this is because cosine goes to zero at the poles. In reality the poles get more light in the summer and no light in winter. A simple way to solve this is just to clamp latitude in our equation to ±66.5°. Why 66.5° ? Well the Earth’s axis is tilted at 23.5° so 90° - 23.5° = 66.5°. If we do this then the polar temperature becomes a nice -30.8°F.

Now we finally have model for planetary temperature that takes solar flux, atmosphere, and latitude into account. This is clearly still very simple and doesn’t include things like altitude, weather, and oceans but it’s a good starting point.

]]>

So what will this game look like? Well, your goal will be to terraform a planet (Mars, maybe Venus ? climate disaster Earth?) but to do this you need to first build a small colony importing resources. Then start up some manufacturing/mining eventually building up a small civilization worth of infrastructure to support massive terraforming machines. I’d like the gameplay to be somewhere between Civ 5 and Factorio with a planetary model similar to how SimEarth worked. This isn’t a fully fleshed out idea by any means but it’s enough to get started.

I figured Unity is a good place to start, I’ve already used it for a few other things and there’s plenty of help available. Next, I decided that hex maps look better than squares. There was just the minor problem that I had no idea how to do that. Squares are nice and easy to work with, just store things in an array and everything lines up. They don’t have hexagonal arrays. Thankfully there is an absolutely wonderful tutorial series for hex maps in Unity here. After finishing those this is what I have:

Noting does anything yet, but I think this is enough for now. Next we can talk about planetary temperature models!

]]>