Chapter 1

Web applications are a very important platform because of their ability to reach a large number of people easily. The ongoing advent of HTML5 and WebGL opens a wide range of possibilities in all areas including Geographical information systems (GIS). Three-dimensional visualizations of the Earth are very modern-looking, popular, and allow us to display some attributes (elevation data, 3D buildings, etc.) that can’t be shown with a classical top-down view.

Many web pages need to present some data to the visitors on a map and sometimes even on a 3D model of the Earth. At the present time, the only way to achieve such 3D visualization is by using closed-source Google Earth API, which requires the installation of a browser extension. Many users are not entitled to perform this kind of operation in the operating system they’re using and need to ask a system administrator to install it for them.

The goal of the WebGL Earth project is to provide an alternative open-source solution implemented in JavaScript and readily available in all WebGL-enabled browsers. The result of this work is a platform-independent 3D application accessible even with modern mobile devices (smartphones, tablets, etc.).

The most technically challenging part of the visualization process is the handling of very large textures (up to 2 billions × 2 billions pixels1). The existing solutions to this problem are described and analyzed in chapter 2. We also describe new methods derived from these that are better suitable for our needs and environment.

The next part of this document (chapter 3) focuses on the actual implementation of WebGL Earth and describes general project design and the inner workings of the most important parts.

This document is written in English so that it can serve as a “guide” to anyone who would like to contribute to the WebGL Earth project or use it as a codebase for some other project.

1.1 Existing virtual globes

As we previously mentioned, there were no WebGL-based virtual globes that would support zooming to street level at the time of writing this document, but there are several standalone applications offering a wide variety of features that could serve as an inspiration to the WebGL Earth project.

One of the most popular and widely used virtual globes is Google Earth. It has a lot of cutting-edge features like 3D terrain or buildings with photorealistic textures. Google Earth also allows users to view a lot of different layers on top of the standard map (state borders, weather overlays, traffic, etc.). One of the most important features is the possibility to display the user’s own data in KML format, which can contain placemarks, vector data, raster overlays or even 3D models. It is, however, quite complicated to add a custom streamable tileset and impossible to insert custom elevation data. Google Earth is closed-source and the interface for user-created plugins is nonexistent. The main reason why Google Earth is the most widely known virtual globe is probably its user-friendliness (simple, but feature-rich UI or KML files opening with one click from the web browser) and the Google Earth API for including 3D maps in a webpage via a plugin.

Another popular virtual globe is NASA World Wind. It has a similar set of features as Google Earth, but it also has better support for user-added content including elevation data and tile layers. NASA World Wind is an open-source, community-driven project that has a lot of interesting features, but is not as straight-forward to use as Google Earth for the typical computer user.

There are also many other virtual globes (osgEarth, Earth3D, Marble, etc.), but they usually support similar features as the two mentioned above.

1.2 HTML5 and canvas element

HTML5 (HyperText Markup Language version 5) is a major revision of the standard for presenting content on the Web. This revision introduces a number of new HTML tags including the canvas element which allows for scriptable rendering of pixel-based images through different contexts. At the time of writing this document, there are two types of contexts available: 2d and webgl (formerly webgl-experimental).

1.2.1 2D context

The first context type that was made widely available was 2D context. It is designed as a state machine (similarly to OpenGL) and can be used for high-performance rendering of two-dimensional objects such as lines, rectangles, arcs, text or bitmap images. The specification also defines methods for controlling shadow rendering or creating gradient fills. The majority of modern web browsers already supports this context type and most implementations are already GPU-accelerated (on certain platforms).

The 2D context can be (together with JavaScript) successfully used to create interactive web visualizations or even web games right in the browser itself.

1.2.2 WebGL context

The second context type enables web developers to create high-performance three-dimensional presentations, which was previously possible only by using browser plug-ins or extensions. The most significant disadvantage of this approach was that the user had to have some additional (often proprietary) software installed (such as Adobe Flash Player or Java Virtual Machine).

WebGL context serves as a binding between high-level JavaScript and low-level GPU operations. WebGL (Web-based Graphics Language) is based on OpenGL ES 2.0 (Open Graphics Library for Embedded Systems) to be easily implementable on modern mobile platforms such as Android or iOS (iPhone OS).

1.3 Graphics pipeline description

In the past, graphics cards were operating in Fixed-Function Pipeline (FFP) mode and programmers didn’t really have much control over the rendering process, because most of the operations (geometry transformation, lightning, texture sampling, etc.) were built into the hardware and could not be programmatically changed.

Modern GPUs use the so-called Programmable Pipeline (or Shader Pipeline) which allows programmers to write special pieces of software (shaders) describing behavior of the pipeline. This can be a very efficient way of creating various effects if used properly. Modern graphics cards contain tens or even hundreds of stream processors and follow the SIMD parallelism model (Single Instruction, Multiple Data). As a result of this, shaders are executed optimally as long as they don’t diverge on different data, so the programmer should try to avoid conditional and loop statements if possible.

WebGL is based on OpenGL ES 2.0 which supports only the Programmable Pipeline (as opposed to OpenGL ES 1.1). The programming language used to write shaders for OpenGL (and WebGL) is called GLSL (OpenGL Shading Language).

Two types of shaders are supported in WebGL architecture:

  1. Vertex shader is a program that is executed “per-vertex” or, more generally, on each element of input data (vertex attributes). These data usually consist of vertex positions, normal vectors, texturing coordinates, etc., but there are no restrictions on input format or semantics. Practically the only restriction is placed on the shader output. Every vertex shader should write its calculation result (final vertex position in screen-space coordinates) to the special variable called gl_Position.
  2. As a part of the rasterisation process, the active fragment shader is executed to calculate the final color of each “fragment” (pixel) where the currently rendered object is drawn and writes it into the gl_FragColor variable. Fragment shaders can be used for simple texture sampling or to create effects like bump mapping or dynamic shadows.

When the vertex and fragment shaders are compiled and linked together we sometimes refer to this assembly as the shader program.


Figure 1.1: WebGL pipeline and storage qualifiers

A storage qualifier affects where a variable’s value originates, where it’s stored, and what operations are allowed to be performed on it depending on shader type. There are five different storage qualifiers in GLSL ES 1.0 [Khr09, pp. 29–32]:

  1. Local variables (default – no keyword)
  2. Compile-time constants (keyword const)
  3. The previously mentioned vertex attributes used to input per-vertex data into the shader. The values of attribute variables are read-only and accessible only from the vertex shader. (keyword attribute)
  4. Uniform variables serving as “execution-time constants” that do not change across the processed primitive. The values of uniform variables are set via API commands and are read-only in both vertex and fragment shaders. (keyword uniform)
  5. The last storage qualifier forms a linkage between a vertex shader and a fragment shader. The vertex shader calculates some per-vertex value (color, texture coordinates, etc.) and writes it into the variable declared with a varying qualifier. When a fragment shader reads from this variable, the value it gets is a result of perspective-correct interpolation between different values written to this variable on the vertices of the primitive where the given fragment originated. (keyword varying)

Relationships between these storage qualifiers and shader types are illustrated by figure 1.3.

It is very important to utilize the computational power of GPU interpolators whenever possible – Many values can be calculated per-vertex with proper interpolation subsequently available in the fragment shader saving some rendering time as there is usually more pixels rendered than triangles in the processed object.

More information about this topic can be found in the OpenGL Shading Language [RK06] or OpenGL ES 2.0 Programming Guide [MGS09].

1.4 Mercator projection

There are many ways of projecting surface of the Earth to a plane. One of the most popular is the Mercator projection, which is defined by the following equations, where λ and φ are longitude and latitude and [x,y] are coordinates of the projected point on the map:

x = λ (1.1)
y = sinh-1(tan(φ)) (1.2)

The principle of this projection is also often described as a balloon (representing the Earth) placed inside a cylinder. The balloon then starts to “inflate” itself occupying the volume of the cylinder. Unrolling the cylinder gives us the resulting map.

Meridians in the obtained coordinate system are regularly spaced, but the distances between circles of latitude increase toward the poles to infinity.


Figure 1.2: World map in Mercator projection

As you can see in figure 1.4, the map preserves angles (which makes the projection conformal) and shapes of small objects. However, the sizes of distant objects are not comparable. For example, Greenland seems to be as large as Africa.

The Mercator projection is also incapable of displaying polar regions properly – the poles themselves would be projected into infinity. Most world maps in this projection are “cut off” at φ = 85.05113 so that the resulting map is square shaped.


Figure 1.3: Mercator tile pyramid

This is very useful when we want to build the so-called “tile pyramid” (figure 1.4), where each layer consists of four times more tiles than the previous one while covering the same area. This means that each pixel in one level of pyramid is replaced by four pixels in the next level giving twice as much detail in each dimension.

Tiles in each level are usually addressed from top-left corner (0,0) to bottom-right (2n - 1,2n - 1). If we know the tilekey (1.3) of the tile we need, we can easily calculate the tilekey of the “fallback” tile (1.4).

tilekey = (zoom,x,y) (1.3)
fallbackTilekey = (zoom - 1,x∕2,y∕2) (1.4)

Such tilesets (collections of images usually with the resolution of 256 × 256px) are freely available from various projects such as OpenStreetMaps (up to level 18) or Bing Maps (including aerial imagery). The same tile system is also used by many other projects including the popular Google Maps.

Interactive web maps are commonly using Spherical Mercator system which uses Mercator projection on the sphere instead of WGS84 ellipsoid. [Při08] [Ope08]

1With 23 zoom levels and 256 × 256px tiles — (223 × 256)2