Tuesday, August 13, 2013

Let's Talk About Planets


It's been a while since I've posted anything, but I certainly have not been idle.  In fact, the reason I haven't posted anything is because I have been so busy!  Usually I get an hour or two every night when I'm back from work/gym to work on this project, and writing blog posts is time consuming.  So usually I get coding instead of blogging, but I don't want to neglect this thing too much.

Sit back, this'll be a long one.

Up until recently, all of my terrestrial planets have been featureless, uniform spheres.  You could land on them, but you couldn't really go sightseeing.  Not so anymore.

I've always been a fan of building up concepts from the bottom, so if we're going to talk about planets the first thing we need to talk about is spherical quadtrees.  Each planet has six faces, which we'll call 'front', 'back', 'left', 'right', 'up', and 'down'.  Initially, each one of these faces is a flat grid of 32x32 vertices.  But planets are not square, so by normalizing the position vector of each vertex we end up with a unit sphere.  Moving these vertices along their normals by the equitorial radius gives us a sphere the size of the planet.

Each of these faces is the root node of a quad tree.  Each quad tree is capable of dynamically subdiving to provide higher levels of detail.  The reasons for this being necessary should be obvious, but I will state them anyway: it would require gigabytes of memory to store all of the vertices necessary to render a planet at a meaningful resolution (say, 5 meters between vertices).  Also, the majority of this fidelity cannot be appreciated when it is on a distant mountain, or from a ship looking down from orbit.  This method reduces the load on the GPU considerably, and consumes much less uncessary memory.

Every level down on the tree covers one quarter of the area of the parent, meaning we can represent more detail with the same group of 1024 vertices.  These subdivision continues until we reach a desired level of fidelity (based on a certain distance between vertices), at which point the node becomes a leaf.  Terrain leaves have collision meshes, and can be stood on.  In order to minimize physics complexity, only active pages (with objects directly above them) and their immediate neighbors have collision meshes.

The SphericalQuadTree class features a series of utilities for finding neighboring tiles given a direction of movement.  These utilities use a series of lookup tables to find the appropriate neighbor, and they even work across the "face" border.  Constructing these lookup tables took a while, and in order to get it right I actually had to make a paper cube that represented the 6 faces of the planet and label it.

With that stuff out of the way, we can talk about terrain generation.

Every planet has a terrain type and a seed value.  From there, we can generate the terrain for the entire planet.  This is done with an interface called the Landscaper, which has several different subclasses for different terrain types.  Every time a new vertex is created in a terrain page it calls a method on the Landscaper and then adds that to the equitorial radius, moving it up or pushing it down.

To do all of the generating I am using libnoise, an awesome open-source coherent noise generation library.

The first important thing to realize is that when I say "type" I don't mean things like plains and mountains.  The terrain type defines what type of planet it is.  Currently I am working on the simplest, called "Barren", to figure out what works and what doesn't.  After that is done, I will implement the others using the techniques from Barren.

Here's an example of what I've got so far (with vertices colored based on altitude):





And here are the currently-planned terrain types:

Barren

These planets are geologically dead (if they were ever very active at all).  Picture these planets looking a lot like the Moon.  They'll usually have rough mountainous areas and relatively flat maria produced by lava flows.  These types of planets will never have an atmosphere, and because of this will usually be heavily cratered.

Irregular

These aren't really planets so much as large captured asteroids.  Mimas is an example of what I'm going for here: a large, oddly shaped ball of rock.  Most of the geological features here will be cracks and craters in the surface.

Magmatic

"Lava" planets are generally young planets which haven't cooled down after their formation.  The Earth was probably like this for the first few million years of its existence.  The surface of these planets mostly appears to be "continents" of cooled magma seperated by gaping fissues of red.  Glowing rivers of lava can be easily seen from orbit.  These planets may or may not have an atmosphere, which would mostly be sulfur and other products of volcanic activity.

Ice

On the exact opposite end of the spectrum are ice planets.  Enceladus and Europa are great examples of these types of planets.  These planets will feature hilly white wastes, sprinkled with craters.  Enceladus also has interesting fractures on the surface caused by tidal stresses from the primary.  Some researchers suggest that Europa may have a sub-surface ocean.  I'm not sure if I'll be able to do something like this, but it could theoretically be modeled with some kind of terrain shell (I will have to think about this).  These planets may or may not have atmospheres.

Martian

I couldn't think of a great name for these, but basically they are relatively-habitable planets with terrain that was shaped by things like wind, dust storms, and glacier movement.  Rivers may appear on these planets, though the liquid is long gone.

Terran

Finally, the gems of the galaxy.  These are what the players are really hunting for if they want their best chance at survival.  These planets are much like Earth, with diverse geological regions and liquid water.  This will be the most difficult terrain generator to implement, and most likely the slowest because of the large number of noise modules needed to generate interesting terrain.

One of the things I want to add on to the basic terrain generation is the placement of monolothic features such as cataclysmic craters and giant mountains a la Olympus Mons.  I'm not sure how I can integrate this with the noise modules, but I will probably have to end up extending libnoise in order to do it.

Also, I mentioned atmospheres in several posts above.  I have a very rudimentary framework in place for atmospheres, but currently they are not actually implemented.  In terms of their actual generation, I'll save that for another post when I actually have something concrete done for it.

Once the actual generation of the physical terrain is complete, I'll be moving on to coloring them.  I have been thinking a lot about how to accomplish the texturing itself.  The planet terrain has a unique vertex class and its own set of pixel and vertex shaders, so I have a lot of freedom to try any methods I want without altering how anything else in the engine is rendered.

One of the first ideas to cross my mind was to do it all procedurally on the GPU, but I quickly decided that it would be too difficult to produce realistic results with only the data available to the GPU.

The idea I am leaning most heavily towards involves several steps.  I won't go into much detail until I actually have something implemented, but here is a rough overview.  First, we take the output of the noise modules determining things like terrian type and "biome" type.  Next, we also need to take into account the angle between the surface normal and the up-vector at that location on the planet (because this changes, the planet is round!) so that we don't get things like grass growing on the side of a cliff.  Once we have some information about the type of ground this vertex represents, we can blend together a palette of available ground textures to get the desired result.

Hopefully soon I'll have some more progress pictures for the different planet types (without textures).  Until then, onward and upward.

No comments:

Post a Comment