The Making of Freeciv WebGL 3D

This is the story of how the 3D WebGL version of Freeciv was created. Some of the most technical challenges of  creating an open source 3D WebGL game will be discussed in this article. Freeciv is a Free and Open Source empire-building strategy game inspired by history, exploration and mathematics, while Freeciv-web is the browser-based version of Freeciv. So we’ll start with Freeciv 1.0 created in 1996, and describe some of the steps it took to create a 3D WebGL version running in a web-browser.

1996 – Freeciv version 1.0. Freeciv was created by the three Danish students Peter Joachim Unold, Claus Leth Gregersen and Allan Ove Kjeldbjerg in November 14, 1995. The first version was created for the Unix platform running on desktop computers and was implemented in C. Freeciv was licensed with the GNU General Public License. The first version used the X Athena Widgets Library (Xaw) and had 2D top-down graphics, and later got 2D isometric graphics.

Circa 2007 – HTML5 version of Freeciv, called Freeciv-web was started. It was made possible thanks to the HTML5 Canvas element which enabled rendering graphics in the browser. Freeciv-web uses a modified version of the Freeciv C server, while the client is implemented in JavaScript. It has 2D isometric graphics.


Freeciv WebGL 3D

WebGL is a JavaScript API for rendering 3D graphics in a browser, and was initially available in 2011. Many users of Freeciv-web started requesting support for WebGL graphics in the game. So on October 23, 2016 the first prototype of a WebGL version of Freeciv-web was created. It was a proof of concept which used the Three.js 3D engine. It rended a simple map, with basic terrain, water and one settler unit.

2016-11-10 A screenshot of the first prototype of Freeciv WebGL. It used a Fragment Shader to render each map tile using separate textures. A heightmap was generated in JavaScript to represent the height of each map tile. Based on the heightmap, the terrain was created using the PlaneGeometry in Three.js, and the position of each vertex was adjusted based on the heightmap. The water was a very large textured flat PlaneGeometry.
At this time the WebGL project got the first contribution of code. Louis contributed improvements to the map rendering, by adding a specular component, ambient occlusion and fade out of the underwater terrain.


2016-11-12 The fragment shader now supported rendering beaches and mountains. Beaches were rendered by the fragment shader by identifying the pixel’s position on the Y-axis.


2016-11-12 Forests are an important part of the game-play, so support for “trees” was added early. Each tree was rendered using a cube geometry in Three.js.


2016-11-20 Cities are another critical part of the game, so that was also added early. At this stage, the WebGL prototype was able to render a static game-state with cities and a few units types.


This image illustrates how Freeciv WebGl implements a terrain with many different tile types. First the image above is generated, where each tile type gets a specified color. This texture is then used by the fragment shader to determine which texture to use from the image below.

This is the texture used to get the different map tile types. It is 1024×1024, because WebGL textures should be power-of-two. Multiple map tile types are included in the same graphics file, because many GPU’s only allow 16 texture units.


2016-11-26 At this stage the work on units had started. Yury Deshko had published Blender models for Freeciv units on in 2011. These 3d models had to be optimized for rendering in WebGL. That meant that the number of vertices had to be reduced to improve bandwith and memory usage. Today the units are exported from Blender to Wavefront (.obj) format, then converted to the Three.js binary format using a script. We want to use the glTF 2.0 format for transferring the 3d models to the browser, but at the moment no good exporter to glTF 2.0 has been found for Blender. Note also the city names, which are not pointing in the direction of the user yet.


2016-12-05 Rendering of unknown terrain and fog of war was then added. The unknown terrain is also a PlaneGeometry mesh, where the vertices are moved around depending on if a tile is visible or not. This was a very naive implementation of the unknown terrain, and we’re still looking for a more efficient method. This inferior method was chosen because unknown terrain is an important part of the game, and it could be improved upon later.


2016-12-10 “Roads” and “Irrigation” was added with even more ugly “programmer-art-graphics”. These tile enhancements are also very important for the game-play, and I just hoped that the graphics quality of these would be imported very soon. The roads and irrigation were textured PlaneGeometry meshes placed over each map tile.

Initial support for blending of map tile borders has been added also.


2017-01-14 In this screenshot the new city labels by Louis can be seen. It uses a custom Vertex Shader to rotate and position the labels correctly in the direction of the user. The label is a textured PlaneGeometry where the text is first rendered to a HTML5 Canvas element, then converted to a Three.js texture. The unit flags are also handled by the same vertex shader.

The cube-based “trees” are replaced by THREE.Points, which have sprite graphics with trees on them.

Roads and irrigation are improved slightly, but are still very ugly.


2017-01-16 More general improvements to the game can be seen in this screenshot. The game is almost playable at this time, but there are still a very long list of known bugs.



2017-01-21 A new WebGL ocean shader has been added. It is based on the Three.js webgl_shaders_ocean example.


2017-01-26 Fog of war and unknown terrain has been improved slightly in this screenshot.


2017-02-19 Support for nation borders has been added to the terrain fragment shader.


2017-03-16 Several improvements have been made to make playing with many units on quite a large map possible.


2017-03-25 Some minor incremental improvements can be seen here. Note that the tile special recources are missing due to some bug when observing a game.


2017-04-04 Many bugs have been fixed  and the game is fully playable at this time. Map tile special resources are rendered correctly.


2017-04-30 The graphics quality is slowly improving, and I’m trying to replace the worst of the “programmer-art” at various places. The roads and irrigation graphics are still very ugly.


2017-05-14 The screenshot shows the updated roads/railroads and irrigation/Farmland graphics. I have finally started to understand UV mapping in Blender and Three.js good enough to be able to map textures to the map tiles in a good way.

Roads and Railroads are implemented in the fragment shader by overlaying sprites over the terrain.


2017-05-21 This is what Freeciv WebGL 3D looks like today.


Future improvements to Freeciv WebGL

There are still many things to improve in Freeciv WebGL.

  • Adding support for WebGL 2.0. This is already supported by the latest version of Chrome and Firefox. However, Three.js needs to add support for WebGL 2.0 first, before it will be available in Freeciv WebGL.
  • Use glTF 2.0 for storing models.
  • Improving the graphics quality, removing “programmer art” and using more textures.
  • Adding Virtual reality and Cardboard support.

Please post your feedback on Freeciv WebGL 3D here or on the forum. We will rapidly publish new releases to the live server and make improvements based on the feedback from users.

Freeciv WebGL 3D can be played here:

Development of the project is on GitHub:


Author: Andreas Røsdal

4 thoughts on “The Making of Freeciv WebGL 3D”

Leave a Reply

Your email address will not be published. Required fields are marked *