Building the Earth with WebGL and JavaScript

Share this article

Of all the HTML5 and related APIs we’ve been given, WebGL is possibly the most interesting. With it we can create awesome 3D environments right in our browsers, and in this article I’m going to walk you through exactly how to do that.

In particular, we’re going to be building a model of planet Earth that we can rotate around like a crazy person and with which we can wow our fellow developers… well, at least a little.

Before We Begin

For this tutorial we will be using the fantastic three.js WebGL plugin. It’s a bit like jQuery for WebGL in that it abstracts a lot of the processing ugliness inherent in the native API. Put simply, three.js makes our lives a lot easier.

We can include it, just like any normal script in our HTML document, like so:

<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/r63/three.min.js"></script>

Here we’ve used a CDN, but you could use a local version. We then need to make sure that WebGL has something to render onto. Here we have some flexibility: we can use an ordinary div or canvas to render directly into the HTML, otherwise we can create and append the canvas later using JavaScript. We’ll go with the first method, to make things a little easier:

<body>
    <div id="container"></div>
    <script src="earth.js"></script>
</body>

After adding the link to the JavaScript file, our HTML is more-or-less done for now.

The Setup

Three.js itself tends to set things up much like a real 3D desktop program might. We have a scene in which things live, a camera with which to view them, some lighting, a renderer to actually render things, and of course the 3D objects themselves. The list can seem a little daunting, but all of these can take shape as variables within our earth.js JavaScript file.

var scene,
    camera,
    light,
    renderer,
    earthObject;

var WIDTH = window.innerWidth - 30,
    HEIGHT = window.innerHeight - 30;

var angle = 45,
    aspect = WIDTH / HEIGHT,
    near = 0.1,
    far = 3000;

There are some other variables defined here, namely the WIDTH and HEIGHT constants to get the width and height for our renderer, and a group of variables we’ll be using later on to set up our camera position.

All of these are elements that are common to almost every 3D project, regardless of the platform or environment, so get used to these guys hanging around. With three.js we’re able to implement these pretty easily, and we’ll see how they fit into our project in a moment.

The Environment

To start, we need to take our new variables and set them up so that our model Earth will show up looking awesome.

We can start by setting up everything that will handle this environmental stuff:

var container = document.getElementById('container');

camera = new THREE.PerspectiveCamera(angle, aspect, near, far);
camera.position.set(0, 0, 0);
scene = new THREE.Scene();

light = new THREE.SpotLight(0xFFFFFF, 1, 0, Math.PI / 2, 1);
light.position.set(4000, 4000, 1500);
light.target.position.set (1000, 3800, 1000);

Here’s a description of what’s happening in the code above:

  • We grab a reference to our container in our HTML
  • We set up our camera using the variables we declared before (for more info on how cameras work in 3D, check this out).
  • We set the camera’s position using position.set, which takes an argument for each dimension (x, y and z). As you may have guessed, we’re going to use this camera to point to our 3D objects, which in this case is our Earth.
  • Next, we set up our light. Without this we’d just have a black screen when we render everything, so we need to set it up pretty carefully. Three.js’s SpotLight object takes more-or-less the same arguments as our camera, but adds the colour in a hexadecimal value as its first argument followed by the rest.
  • Lastly, we set up our renderer. Another vital piece of the puzzle, the renderer actually renders the scene we’ve made onto the screen; again, without it we’d see nothing but the darkness of space. We give it anti-aliasing (for some smooth-ass surfaces) and append it as a DOM element to our original container.

Now we need to start building Earth itself by sticking in a mesh:

var earthGeo = new THREE.SphereGeometry (30, 40, 400), 
earthMat = new THREE.MeshPhongMaterial(); 

var earthMesh = new THREE.Mesh(earthGeo, earthMat); earthMesh.position.set(-100, 0, 0); 
earthMesh.rotation.y=5;

scene.add(earthMesh);

Here we create a mesh, which is kind of like an object that we’ll dress up to look like Earth, and give it some geometry and a material, or texture, to cover it. We also position it properly and add it to our scene like we did with our other objects. 

You can see an example of our setup below. There is some extra code here to handle the rendering (which we’ll get to in a moment), but it’s looking good so far!

See the Pen WebGL Earth Tutorial, Demo 1 by SitePoint (@SitePoint) on CodePen.

The Blue Planet

Now the fun part is skinning this guy. First we’ll use a diffuse map, which will give us the look of Earth, and which you can add like this:

// diffuse map
earthMat.map = THREE.ImageUtils.loadTexture('images/earthmap1k.jpg');

If you’re in need of a good texture to use here, you can try this one or search Google for a decent diffuse map of Earth. Anything with a good resolution is fine.

Now this doesn’t look too bad, but we can make it better by introducing a little topography here. The Earth has some pretty high mountains and in order to make sure the rest of the solar system knows that, we’ll need to use a bump map. In 3D, bump maps are black and white images, with the intensity of white indicating the height of the “bump” (or in our case, our mountains).

// bump map
earthMat.bumpMap = THREE.ImageUtils.loadTexture('images/elev_bump_16ka.jpg');
earthMat.bumpScale = 8;

With that, we’re more-or-less there. Again, searching Google for “Earth bump map” will give you plenty of options, but if you don’t feel like hunting you can find a nice one here. If we run the above code (with the rendering code from before), we’ll get this:

See the Pen WebGL Earth Tutorial, Demo 2 by SitePoint (@SitePoint) on CodePen.

Spin It!

All that’s left now is to give our Earth some rotation. We’ll need two new functions for this, which we can call render() and animate().

function animate() { 
   requestAnimationFrame(animate);
   render(); 
}

Our animate() function isn’t too complicated. It calls itself continuously using requestAnimationFrame() and each time it does, it calls our render() function. Let’s get to that render() function next:

function render() { 
   var clock = new THREE.Clock(),
       delta = clock.getDelta(); 

   earthMesh.rotation.y += rotationSpeed * delta;
   renderer.render(scene, camera);
}

Here’s where things are happening. Every time render() is called, it spins our Earth a little bit on the y-axis (you can choose any amount to rotate by here; we’re using a built-in clock with a getDelta() method in this case, but you don’t have to). It then clears our renderer, a necessary step to avoid render ugliness, and renders our scene (with everything in it) and our camera.

To The Bitter End

There are, of course, tweaks we can add to make our Earth even better. OrbitControls.js is a script that will give some mouse-driven rotation ability to our Earth and adding a field of stars to our backdrop or some clouds in our stratosphere isn’t too difficult either. If you’re a real sucker for punishment, you can even add an atmosphere to your planet using WebGL’s shaders.

You can see an example, with code, of some of these additions in the final CodePen demo:

See the Pen WebGL Demo Final by SitePoint (@SitePoint) on CodePen.

Be sure to click around on the page and scroll your mouse wheel to see the special effects (hold down shift to get the mouse wheel working on this page or else use the full page demo).

Conclusion

WebGL and three.js can be challenging because they require us to think a little like a 3D artist at times, using things like scenes, renderers, and cameras to get the job done.

But the result is something that looks pretty impressive and, if you’re dedicated, can lead to some interesting possibilities with 3D in the browser. Stick with it and you’ll be able to pull off some amazing feats in no time.

Frequently Asked Questions (FAQs) about Building Earth with WebGL and JavaScript

How Can I Add More Realistic Textures to My WebGL Earth Model?

To add more realistic textures to your WebGL Earth model, you can use high-resolution images of the Earth’s surface. These images can be sourced from NASA’s Visible Earth catalog. Once you have the images, you can map them onto your 3D model using UV mapping. This involves assigning each vertex in your model a coordinate in the 2D texture image. The WebGL renderer will then interpolate these coordinates to paint the texture onto the model’s surface.

How Can I Implement a Rotating Animation for the Earth Model?

Implementing a rotating animation for the Earth model involves updating the rotation of the model over time. This can be achieved by incrementally adjusting the rotation angle of the model in the animation loop. You can use the requestAnimationFrame function to create a smooth animation loop, and update the rotation angle of the Earth model in each frame.

How Can I Add Other Planets or Objects to the Scene?

Adding other planets or objects to the scene involves creating new 3D models and adding them to the scene. Each model will have its own geometry, material, and texture. You can position the models in the scene using their position property. To animate the planets, you can update their position and rotation in the animation loop.

How Can I Implement a Zoom Functionality?

Implementing a zoom functionality can be achieved by adjusting the camera’s position or its field of view. You can listen for mouse wheel events and adjust the camera’s position or field of view based on the wheel delta. This will give the effect of zooming in and out of the scene.

How Can I Add a Starfield or Galaxy Background to the Scene?

Adding a starfield or galaxy background to the scene can be achieved by creating a large sphere that encompasses the entire scene, and mapping a starfield or galaxy texture onto it. This sphere should be rendered before any other objects in the scene, so it appears as the background.

How Can I Improve the Performance of My WebGL Application?

Improving the performance of your WebGL application can be achieved by optimizing your code and assets. This includes minimizing the number of draw calls, reducing the complexity of your models, and using efficient algorithms for calculations. You can also use WebGL extensions to take advantage of hardware acceleration.

How Can I Make My WebGL Application Responsive?

Making your WebGL application responsive involves adjusting the size of the renderer and the camera’s aspect ratio based on the size of the browser window. You can listen for window resize events and update the renderer size and camera aspect ratio accordingly.

How Can I Add Interactivity to My WebGL Application?

Adding interactivity to your WebGL application can be achieved by using event listeners to detect user input, such as mouse clicks or touch events. You can then update the state of your application based on this input. For example, you could allow the user to rotate the Earth model by dragging the mouse.

How Can I Debug My WebGL Application?

Debugging your WebGL application can be done using the browser’s developer tools. You can use console.log statements to output information to the console, and the debugger statement to pause execution and inspect the state of your application. There are also WebGL-specific debugging tools available, such as WebGL Inspector.

How Can I Learn More About WebGL and 3D Graphics Programming?

There are many resources available for learning more about WebGL and 3D graphics programming. This includes online tutorials, books, and courses. Some recommended resources include the WebGL specification, the book “WebGL Programming Guide”, and the online course “Interactive 3D Graphics” by Udacity.

Byron HouwensByron Houwens
View Author

Byron Houwens is a designer and developer who enjoys focusing on front end technologies and UX. He currently works as a front end developer in the burgeoning edtech environment, and lives in sunny Cape Town, South Africa.

3DLouisLthree.jsWebGL
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week