WebGL weather globe

When watching both weather show visualisations, disappointingly local in time and space, and looking at static pictures of global air circulation like here, I always wondered about a way to combine both and have a long-time, global view, preferably on a sphere rather in some crazy projection and with a slider to freely navigate in time… Recently I though it would be nice to learn some WebGL, and that seemed to be a cool first project. So I made this; the whole thing has some rough edges, but is certainly enough to see some well known phenomena like seasons, impact of the continent masses, jet streams, trade winds, roaring forties, even some cyclones (though hurricanes are probably too fast to survive daily averaging). WeGL weather globe screenshot You can find the whole code on Github, including data pre-processing; it should be pretty self-explanatory, though I’ll summarise the most important ideas.

The data come from NCEP/NCAR 40-year reanalysis, a project which collected tons of measurements since 1948, run a quite good, global meteo forecast model over it and published the results in a convenient form. In case you wonder why to hell anybody would want to run a forecast model to predict past events rather than do some kind of interpolation, the answer is fairly complex but boils down to the fact that essentially forecast models are just the best way of de-noising, integrating and interpolating weather measurements. Obviously the accuracy of such thing is far from stellar, moreover I’m using only a single year and a heavily down-sampled version of the whole output for convenience; yet it should be OK for the purpose.

The visualisation is showing 2 fields, one scalar, average daily temperature near the surface, and one vector, horizontal wind near the surface. Both are represented on a regular 144×73 grid within Mercator projection of the Earth; this is both bad because polar areas are overrepresented and good because it is easy to map this over sphere. Whole data is pushed to the user’s browser as a single PNG file; individual time frames are combined vertically into a strip (like a movie tape), while temperature, WE wind component and NS wind component are placed into RGB channels of the image. Since PNG supports only a 8bit resolution, each value was clipped to a pre-defined interval (-50 to 50 centigrade for temperature and -40 to 40 m/s for wind) and normalised to the 0-255 range. Thanks to PNG built-in compression the whole thing weights about 6MB, which is pretty reasonable; it is probably possible to have greater reduction by using JPEG, yet with a significant risk of some crazy artefacts.

Finally, the rendering. I’m using three.JS to deal with WebGL; the scene is just a SphereGeometry mesh, and the heatmap, wind barbs and coastline are drawn by a custom fragment shader. I wanted to make a time interpolation, so the data goes into it as two textures, one for frame before required time, and one after, and they are averaged with a weight given as an uniform inside the shader. Obviously linear interpolation is not a perfect choice and leads to a bit electro-boogie like jumpiness of the animation, but is good enough for me. Both textures are made on invisible canvas because I additionally warp the field horizontally to make it wrap on data line rather than prime meridian, and add a copy of the first column to fix UV mapping in three.js without having to use OpenGL texture repetition which requires power-of-two texture dimensions are is problematic overall.

Heatmap is done by sampling a palette loaded as a texture with the value of the blue channel of the time-interpolated data texture. Barbs are done in a similar manner than in this arrow shader, yet tweaked to the spherical geometry; sampling grid gets sparser horizontally near the poles, and the angle/distance to the sampling grid node required to paint the barb are replaced with great circle bearing and distance formulae. For simplicity, barbs are just painted as an wind vector – pixel azimuth angle to the fourth power isoline shape rather than a proper arrow. Honestly, there are probably better ways to define the barb grid and avoid certain problems near the poles… but this is a topic for a further experimentation (;

Finally, shader mixes heatmap with barbs and adds the coastline given as a standard texture, build from the Natural Earth’s 110m coastline (first converted to SVG in QGIS, later rasterised into PNG).

Previously: Cardboard container, later: So, you want to optimise something?.

CC-BY mbq, written 13-8-2015, last revised 28-7-2018.