Andrew Huynh
Thoughts 
and ramblings.
Email me!
Follow me on Twitter!
Check me out on LinkedIn.

TBT: Planet Rendering

2017 May 18 - San Francisco | 1058 words

#gamedev #3d

Many moons ago, I worked on a college project that required procedurally generating a "realistic" planet in 3D space. The original implementation created a mesh in the form of the UV sphere and then applied a particle deposition to create the terrain.

I thought it would be a fun project to revisit my implementation and use modern tooling to re-create what I had done close to 10 years ago in vanilla javascript and WebGL with Typescript and Three.js.

You can view the old project and newer code used in this post here.

Rendering the sphere

The UV sphere was originally chosen due to time constraints. The code (shown below) to generate a UV sphere is relatively compact and easy to follow making for a quick implementation and allowing us to focus on the terrain generation and animation used in the project.

1 // Columns
2 var gamma = 0.0;
3 var gammaStep = 2 * Math.PI / numFaces;
4
5 // Rows
6 var theta = 0.0;
7 var thetaStep = Math.PI / numFaces;
8
9 // Loop through each row & col in spherical coordinates.
10 //
11 // Note: numPoints = numFaces + 1. You need n + 1 points to
12 // represent n faces.
13 for(var row = 0; row < numPoints; row++) {
14 gamma = row * gammaStep;
15 for(var col = 0; col < numPoints; col++) {
16 theta = col * thetaStep;
17
18 // Convert to cartesian coordinates
19 var x = Math.sin(theta) * Math.cos(gamma);
20 var y = Math.cos(theta);
21 var z = Math.sin(theta) * Math.sin(gamma);
22
23 var v = new Vector3(x, y, z).normalize();
24 this.vertices.push(v);
25 }
26 }

Using latitudinal and longitudinal lines as a grid, we can loop through each row/column and generate points for the sphere.

Combining the above code with some Three.js materials and lighting, we get the following scene below, a blank canvas in which we can start transforming the surface into believable terrain. Unfortunately at the time, we didn't notice how the area of the faces changed as you moved closer to the equator and poles of the sphere. As you'll see later on, this will come back to bite us when we start to apply the tranformations.

Now onto the terrain generation! How do we take this flat spherical surface and turn it into the rugged planet we want for our scene?

Particle Deposition

Particle deposition starts with a single point and slowly builds out a land mass around that area by randomly moving different directions adding additional height displacement as it goes. If we'd like, at the end of the terrain generation we can then apply a smoothing function on the resulting land mass to make it look a little less jagged.

    for( var i = 0; i < numIslands; i++ ) {
        // Find a random spot on the planet to grow an island
        var sx = randomInt( 0, width );
        var sy = randomInt( 0, height );

        for( var itNum = 0; itNum < iterations; itNum++ ) {
            // Add the displacement to the current height
            set( sx, sy, get( sx, sy ) + displacement );

            // Pick a direction to go next
            switch( this._randomInt( 0, 3 ) ) {
                case NORTH: sx = sx + 1; break;
                case EAST:  sy = sy + 1; break;
                case SOUTH: sx = sx - 1; break;
                case WEST:  sy = sy - 1; break;
            }
        }
    }

Note that it's possible to continue moving along a single direction, generating a ridge. We can box in land masses by making sure future directions are with n of the initial growth point.

To see the results of the above code, lets start off with a single landmass and apply particle deposition. In the following example, I've bumped up the resolution of the sphere so that a single island is more noticeable.

Trouble in Paradise

As we continued with the terrain generation, one of the main issues we faced was due to how a UV sphere is represented in 3D space. As mentioned previously, the sphere is divided up into meridians and parallels, which creates an effect where faces towards the top and bottom of the sphere are smaller and more bunched together, while the faces that are closer to the middle of sphere are larger and more spread out.

Fun fact: This sort problem also exists in how we represent Earth. Different map projections will show landmasses in different ways and may distort the actual area/size/shape.

This distortion can be seen in full effect by bumping up the number of land masses. It wasn't ideal, but since we were only using the planet as part of an animation, as long as we focused on the mid-section of the sphere the distortion isn't as evident.

For Next Time

In the next post, we'll look at how we can apply height based vertex coloring to give our planet more personality as well as other sphere rendering methods that lead to a more natural looking planetoid.

Hope you enjoyed this short foray into sphere rendering and terrain generation.

You can view the old project and newer code used in this post here.

Edits