Tuesday, September 9, 2014

Game-development Log (4. Rendering image tiles)

Work-in-progress: https://site-win.azurewebsites.net

New iteration, tons of new stuff:
  • Create a mixed-approach for the problem of having data pre-generated vs generated on-the-fly
  • Binary Vector Tiles
  • Render image tiles
  • Blending with Bing Maps
  • Improved loader process to fix/optimize roads and railways

So, let me explain each of these items:

Create a mixed-approach for the problem of having data pre-generated vs generated on-the-fly

On my previous posts I presented one of my major concerns: choosing a proper data-store for the hexagon data. I thought about Redis, Table Storage or eventually pre-generating the whole lot: both vector tiles and image tiles.
On my last post I was tending to just generate the vector tiles and generate the image tiles dynamically. As I was implementing it I had an even better idea:
  • Store the vector tiles for the furthest way zoom level (in my case 7) on the Azure blob-storage.
  • Then, when a zoom level other than 7 is requested, simply dividing consecutively by 4 provides the required tile, due to the nature of the map-tiles.
Reference: Bing Maps Tile System
Just to provide some comparison data on the impact of this, if I stored the whole world in zoom level 7 that would correspond approximately to 20.000 tiles, which is pretty reasonable. Storing everything until level 13 (which is what I plan to support) would require about 90.000.000 tiles. But even worse than the space occupied would be the time required to generate all these tiles. Without a proper infrastructure it could take months, with the added impact of making changes nearly impossible.

Performance-wise I'm currently quite happy with the loader process. Loading terrain, altitude, roads, railways, forests, country-info and urban areas for Portugal (including persisting the vector tiles on Azure Blob Storage) takes about 30 seconds. Not brilliant but not a bottleneck. Eventually loading big countries like the United-States could take a couple of hours.

Note: To optimise it even further I only store the vector-tiles that contain any data. Eventually, when I've mapped the whole world, only about 1/3 will require tiles as 2/3 is water.

Binary Vector Tiles

On my first approach the vector tiles were being stored on Azure Blob Storage as text/json. I then changed the implementation to also support binary data. The results were satisfactory: less size occupied on the blob storage (and on the wire when uploading) and faster serialization/deserialization. I still support the JSON format but the default is now the binary one.

Added Drawing-logic to generate image tiles

On my previous post I've described what a vector tile is. For example, a simple one:


Inspecting the content one can see that it has various info, including a road element (with a numerical element that represents a mask with the edges that are crossed by the road)

I've implemented the image rendering mechanism. The corresponding tile-image for this vector tile is:


Other examples of image tiles generated on-the-fly based on the Vector Tiles:

It's important to note that this is not the final look&feel for the image tiles. I plan to experiment with textures, eventually loading different terrain types (like crops, desert), etc.

I'm currently supporting:


Roads, including intersections. I'm currently just loading motorways.

Altitude information, currently shading the hexagons according to this value. In the short-term I'm going to do something different, eventually on my next blog post.

Railways, following a similar logic to the roads

Urban areas. This is a little bland and I'm not exactly sure on how to make this represent urban-like stuff.

The most basic info of all: land.

I've got tons of other ideas, like displaying labels, cities, borders, administrative areas.

Blending With Bing Maps

As I've mentioned above, I only generate hexagon tiles from zoom level 7. Below that (i.e, with lower zoom levels) the hexagon edge size wouldn't even be 1 pixel wide thus not making much sense to display them. Thus, one of my concerns was:

"What map layer should I display between zoom level 0 and 6?"

I thought on various alternatives, including generating my own tiles from real vector data (using TileMill / Mapnik) or splitting a real satellite image. Anyway, the most important requirement was tha between zoom 6 and 7 the transaction needed to be as seamless as possible.

Then I had a cool idea:

Between zoom levels 7 and 10 blend my hexagons with the Bing Maps colors on the the various components: water, land, forests and roads.

So, here's the effect while zooming out:


Colours start fading

The hexagons are now much brighter, mostly noticeable on the forest hexagons.

Most of the colours are now pretty much similar to the Bing maps ones

The hexagon layer is hidden and the Bing Maps imagery is displayed

Still not perfect but good enough for now.

Improved loader process to fix/optimize roads and railways

One of the problems that I had with the roads and railways was the fact that, as the hexagons have a finite range of options for displaying roads it's incredibly likely that lots of strange hexagons are generated, particularly as the process is totally automatic.

A picture is better than a thousand words, so take a look a this example. Portugal is actually a great candidate for this problem as it has an incredible amount of motorways given its small size:

I've created a "road-fixer" process that cleans-up the roads. After execution the same area now looks like this:

Not perfect but MUCH better.

I've deployed all of this on Azure. You can try it out at: http://site-win.azurewebsites.net/Map/V2 (link no longer working)

Note: Randomly some tiles are generated without any data. That's a GDI+ problem that I haven't yet fixed

No comments:

Post a Comment