Render 3D Buildings in Geospatial WebGL Visualisations

Render 3D Building Models with MapboxGL, MapTalks & Three.js from 2D GeoJSON

Charmaine Chui
October 8, 20216 min read

Hands-on Tutorials

Screenshot by Author | The final output rendered in MapboxGL | Showcasing the HDB Building Layer of Singapore | Deployed at SG HDB Building Layer in MapBox WebGL
Screenshot by Author | The final output rendered in MapboxGL | Showcasing the HDB Building Layer of Singapore | Deployed at SG HDB Building Layer in MapBox WebGL

Inspiration for Side Project

For the past few months, several countries have made it public service to showcase map visualisations of COVID Hotspots within their countries. Some off the bat examples include Jakarta & Singapore:

Screenshots by Author | Left Screenshot is captured from Peta Sebaran | Covid19.go.id (Jakarta's COVID Map Viz) | Right Screenshot is captured from Ministry of Health (moh.gov.sg) (Singapore's COVID Map Viz)
Screenshots by Author | Left Screenshot is captured from Peta Sebaran | Covid19.go.id (Jakarta's COVID Map Viz) | Right Screenshot is captured from Ministry of Health (moh.gov.sg) (Singapore's COVID Map Viz)

While seeking a side project to explore, I had been tasked at work to create the map on the right, a feat which I had speed blitz in a couple of hours. To my immense surprise that piece of work made headlines in my country for a couple of days, exceeding my expectations completely.

With more attention garnered on maps as well as the field of Geographic Information Systems (GIS), I decided to shift the scope of my next side project to be GIS-related as well. Thereafter I started browsing through pieces of works online for inspiration and came across a project at Release of 3D building open data of HDBs in Singapore | Urban Analytics Lab | Singapore (ual.sg)

Screenshot by Author | The 3D building layer of Residential flats in Singapore documented at Release of 3D building open data of HDBs in Singapore | Urban Analytics Lab | Singapore (ual.sg)
Screenshot by Author | The 3D building layer of Residential flats in Singapore documented at Release of 3D building open data of HDBs in Singapore | Urban Analytics Lab | Singapore (ual.sg)

Note: Do check out the above piece of work by the research team because it is really a wonderful project by them 😄

Since the data sources were open-sourced and available for public use, there is no risk of confidentiality breach and hence I decided to embark on my own journey to re-enact what the team has done - Render the residential buildings in Singapore onto a 3D map but with my own tweaks and modifications in place.


List of Data Sources & Data Processing Steps

Data Source (1/3): HDB building Information Dataset

The key data fields to note in this dataset would be:

Illustration by Author | Since the dataset contains no spatial information, both "Block number" & "Street" values can fortunately be used for subsequent geocoding to derive its latlng coordinates instead.
Illustration by Author | Since the dataset contains no spatial information, both "Block number" & "Street" values can fortunately be used for subsequent geocoding to derive its latlng coordinates instead.

Data Source (2/3): List of Singapore's Addresses & Postal Code

Objective: Geocode each residential building's Point coordinate

While the research team at Urban Analytics Lab made use of a map service provider known as OneMap, since I had a list of up-to-date addresses streamed from the exact same API, I had to merely do a mapping between the relevant fields to tag the [Latitude] & [Longitude] coordinates to each building:

Illustration by Author | Tagging each building to a unique postal code value and [Latitude] + [Longitude] fields enables each building block to be spatially plotted on the map
Illustration by Author | Tagging each building to a unique postal code value and [Latitude] + [Longitude] fields enables each building block to be spatially plotted on the map

— To find out how to crawl the list of addresses within a Region/City/Country, please refer to my below article (with code implementation):

How I crawled the entire list of postal codes in a country with Java

The output file from this step can be found at my GitHub link: HDB_Only.json

To convert the file into GeoJSON format, I used simple JavaScript and derived the following:

However, since the above output provides only the Point Coordinates of the building blocks, I had to source for the Polygon Shape Geometry of each building elsewhere.

Recall that the outcome of this project is to output the 3D model of each building. Hence a prerequisite would to attain the 2D Polygon shapes corresponding to each building block.

Data Source (3/3): Building Layer of Singapore from data.gov.sg

At this point, instead of mimicking what the Urban Analytics Lab team has done i.e. use the building footprints provided by the OpenStreetMap (OSM) community, I had instead retrieved the spatial dataset from the same data source as the building information at data.gov.sg instead.

Data Processing Step [1/2]: Separating Polygon Geometry Objects from GeometryCollection Arrays

While the building layer dataset contains all the building footprints required, in order to easily enact the 3D mesh of each residential building, I decided to extract all the embedded Polygon Geometries from its several GeometryCollection arrays into individual Polygon objects.

Rationale: Processing each building as a 2D Polygon and then extruding it would save a lot of subsequent data processing required at the rendering stage as compared to reading in the arrays of nested Polygons.

After assigning the identifier fields [ID] & [SUBID] to each Polygon Object, I managed to derive the following spatial file named: building_layer.geojson (please note that file size is over 30MB)

Data Processing Steps [2/2]: Tagging each Polygon to Point Building

Using functionalities of TurfJS, I proceeded to leverage on a GIS tool I had deployed at Tableau Data Utility under the [Geocoder Tool] Tab:

Screenshot by Author | This was a GIS utility tool along with other Tableau utility tools selectable from the header menu which I have created for some of my other articles | Accessible at: https://tableau-data-utility.onrender.com/
Screenshot by Author | This was a GIS utility tool along with other Tableau utility tools selectable from the header menu which I have created for some of my other articles | Accessible at: https://tableau-data-utility.onrender.com/

In essence, the above tool leverages on the JavaScript library TurfJS to cross-check which each Point coordinate overlaps with any of the Polygon Geometries uploaded.

Illustration by Author | TurfJS returns a boolean value of whether a Point coordinate is within the boundaries of a Polygon geometry
Illustration by Author | TurfJS returns a boolean value of whether a Point coordinate is within the boundaries of a Polygon geometry

For those who are interested in this tool, feel free to check out the below article which goes in-depth into how TurfJS is implemented for Geocoding based on custom boundaries:

Using Turf.js to Geocode coordinates with custom boundaries

The resulting output consist of unique Polygon identifiers [ID] & [SUBID] tagged exclusively to each Point coordinate. Thereafter, based on these identifier fields, the resulting residential building Polygon layer is finally output as: hdb_building_polygons.geojson (please note that file size is over 30MB)


3D Rendering of HDB Residential Building Layer of Singapore

Altogether I had 2 approaches for modelling the residential buildings in Singapore. In both scenarios, the [no. of floors] is used as a proxy for the building heights rendered onto the map.

Implementation 1) MapBoxGL JS

Image by Author | Demo of 3D modelled map on MapBox WebGL | Deployed at the link below
Image by Author | Demo of 3D modelled map on MapBox WebGL | Deployed at the link below

SG HDB Building Layer in MapBox WebGL

The source code for this can be found at my GitHub Repo: Link

Implementation 2) MapTalk JS + ThreeJS

However, much as MapBoxGL JS renders spatial files beautifully, it is a challenge to showcase 3D Maps in the event that - (1) Internet accessibility is not present or (2) If the Map service provider is offline since this would disable **** the 3D features of the Geometries. To account for such a scenario, I explored alternatives and came across MapTalk JS + ThreeJS.

The resulting local implementation of the 3D Building Models in ThreeJS + OneMap Basemap (a pure offline-setup) is as such:

Image by Author | The resulting 3D buildings rendered with ThreeJS | The mesh of each building is rendered based on each polygon's vertices | Grey Scale One Map Basemap is rendered offline with mbtiles
Image by Author | The resulting 3D buildings rendered with ThreeJS | The mesh of each building is rendered based on each polygon's vertices | Grey Scale One Map Basemap is rendered offline with mbtiles

Conclusion: Thoughts on MapBoxGL & ThreeJS

In summary, while [MapBoxGL](http://mapbox.com) offers a much quicker form of implementation as compared to [ThreeJS](https://threejs.org/), the latter however enables greater forms of customisation such as lighting & camera perspective. Evidently by comparing and contrasting both of my above implementations, the lighting reflected on the building mesh looks less obscured in MapBoxGL as compared to ThreeJS since I did not take into account the calculations for the lighting and angle of camera.

Further Exploration:

Between the 2, ThreeJS definitely has greater potential for exploration since it is catered to many other 3D modelling domains and not solely Geospatial. However in many cases due to the interest of time MapBoxGL is still a primary candidate to consider for rendering 2D Geometries onto a 3D map.


Many thanks for persisting to the end of this article! ❤ Hope you enjoyed the recount of my side project and feel free to follow me on Medium if you would like more GIS, Data Analytics & Web application related content. Would really appreciate it 😀 TGIF!

Related Articles