Procedural Planets

Let's turn the terrain rendering up to 11 Posted in:

screenshot of a planet rendered from low orbit
Normal-mapped planet.

The semester is over at last, and my grades should be in by Monday. It has been a tiring semester, but not a bad one, with interesting courses in database implementation and parallel architectures, not to mention philosophy.

With the end of the semester comes a little more free time, and I have spent a chunk of it recreating my old procedural planet demo in Python/Pyglet.

The first big plus is that whereas my previous implementation was over 5,000 lines of C++ code, the python version is under 1,000 loc, plus a few hundred lines of tightly optimised C for the tile generation back end.

The other plus is that this version actually works. I finally found the time to fully implement the crack fixing algorithm, and the results are very good (although there are still a couple of unresolved edge cases).

I also implemented normal map generation in GLSL, to offload the computation to the GPU. This more than doubles the performance of tile generation, to the point where several tiles can be subdivided or combined each frame.

screenshot of the wireframe of a planet rendered from low orbit
Wireframe of planet.

From a technical standpoint, the planet starts as a cube, and each face is subdivided to form a quad tree. For each tile at the deepest level of the quad tree, a small heightmap is generated using 32 octaves of 3-dimensional simplex noise. This heightmap is used to generate the vertices for the tile, and passed as a texture to the GPU in order to generate the normal map.

Because applying tangent-space normal maps to a sphere is an absolute nightmare, I take the unusual approach of generating object-space normal maps. These are considerably more expensive to generate, but avoid the tangent-space mismatch at cube edges, and look fairly decent in practice.

Interestingly, this version allows one to fly right down to the planet surface, and maintains interactive framerates even on my Intel integrated X3100 (complete with the awful Mac drivers). By the time I add atmosphere shaders and detail textures, I expect that I will have to switch over to my desktop, but for now, I am very happy with the performance.

Of course, there are still several challenges to overcome, in particular the issue of depth buffer precision. The planet you see above does not suffer from a lack of depth buffer precision, but it is only 1/10 scale of the Earth, and ideally I would like to be able to render gas giants on the order of Jupiter as well. This requires some clever on-the-fly adjustment of the camera frustum, and I don’t quite have a handle on the best way to accomplish it.