HOW TO : Make Parametric Buildings

One common use-case for osgEarth is to load a shapefile (or other feature source, like WFS) and generate extruded buildings. These are what we call parametric buildings because osgEarth generates them at run-time based on a series of inputs. (This as opposed to an external model, which is a 3D building model created in some other application and imported into osgEarth.)

NOTE: In this HOW-TO we'll be doing the work in an earth file, but the same technique applies to using the API.

Set up the source data

Start with a feature source (a shapefile or other source of geometry) that has building polygons. These polygons form the outline of the base of the building. Begin by building a model layer with a feature source like so:

   <model name="Buildings">
      <features name="building footprints" driver="ogr">
         <url>my_buildings.shp</url>
      </features>

      <styles>
         ...
      </styles>
   </model>

In this example, we're using the OGR driver since it can read a shapefile. The <styles> block is where we will put the symbology information needed to create the building models ... but that will depend on some other factors.

Determine the building height

Since we're going to extrude these footprints into 3D buildings, we need to know how tall to make the building. These are the most common scenarios:

  • Each feature has an attribute with the actual building height (in some units).
  • Each feature has an attribute with the rooftop elevation (relative to sea level)
  • You have NO height information.

Let's look at how to handle each scenario below.

Actual building height

In this case, each feature record has an attribute containing the height of the building (above the ground). We need to assemble a style sheet. It will look like this:

   <styles>
      buildings {
         altitude-clamping: terrain;
         extrusion-height:  [height] * 0.3048;
         extrusion-flatten: true;
      }
   </styles>

The altitude-clamping property is telling osgEarth that prior to doing anything else, it needs to modify the feature geometry so that all the points are clamped to the terrain. Most footprint data is 2D -- it doesn't have a Z value. So we need to assign Z values prior to extruding the walls of the building.

The extrusion-height is an expression that evaluates to a value for each feature that osgEarth processes. When you enclose an identifier in square brackets "[]", osgEarth will read the value of the named attribute from the current feature. If you need to, you can also apply simple mathematical operations to the read value -- in this case, we're converting it from feet to meters.

Finally, extrusion-flatten tells osgEarth to make a flat roof. If you building was on the side of a hill, and we extruded each wall to the same height, the roof would follow the same contour as the terrain. For buildings, that is not usually what we want. This property deals with that.

Rooftop elevation

Some building data has an attribute specifying the absolute elevation (above MSL or the Ellipsoid) of the roof. This is common when the data was extracted from LIDAR or some other scanning technique (as opposed to photogrammatric extraction, which typically yields building heights).

In this case, we need to handle things a little differently. Here's the style sheet:

   <styles>
      buildings {
         altitude-clamping: absolute;
         altitude-offset:   [elevation];
         extrusion-flatten: true;
      }
   </styles>

Here, instead of extruding up from the terrain, we will actually be extruding down from the rooftop. The altitude-clamping property of absolute tells osgEarth that it will extruding down from an absolute Z in the feature geometry. The altitude-offset tells osgEarth what the absolute elevation is (again notice we are reading it from a feature attribute via the [] notation) and applies it to the geometry. It also enables osgEarth to sample the terrain under the building so it knows just how far to perform the downward extrusion.

No height data

In this case, you are stuck with telling osgEarth how far to extrude the data. You can give it a static number (in meters), or you can use scripting to generate the data some other way.


Applying color

Now that we have extruded 3D buildings, we can focus on how they look. You can apply a solid color to your buildings by using a simple fill symbol:

   buildings {
      altitude-clamping: terrain;
      extrusion-height:  [height] * 0.3048;
      extrusion-flatten: true;
      fill:              #ff00007f;
   }

An "HTML-style" color string encoded the RGBA components of the polygon color as hexidecimal values. This example is translucent red.

Applying textures

Applying textures to the building facades and rooftop is a little more involved. Again, keep in mind that we are making parametric buildings -- we are not going to apply a unique photographic texture to each individual building; rather we want the buildings to look appropriate for the scene. (To make unique photo-real buildings, consider using substitution of external 3D models instead.)

Extrusion textures are called 'skins'. A 'skin' couples an image with some metadata that describes how that image can be used (including data like its real-world size and appropriate height range). Skins reside in a resource library ... that's another topic.

Here is our basic setup for building texturing:

   <library name="mylib">
      <url>resources/catalog.xml</url>
   </library>

   <styles>
      buildings {
         altitude-clamping:    terrain;
         extrusion-height:     [height] * 0.3048;
         extrusion-flatten:    true;
         extrusion-wall-style: wall;
         extrusion-roof-style: roof;
      }
      wall {
         skin-library:         mylib;
         skin-tags:            building commercial;
         skin-tiled:           false;         
      }
      roof {
         skin-library:         mylib;
         skin-tags:            rooftop;
      }
   </styles>

The extrusion-wall-style property points to another style (in the style sheet) that defines how to walls should look. In this case it's called "wall". It says:

  • Look in the "mylib" resource library;
  • Consider only textures with both the tags "building" and "commercial"
  • Consider only non-tiled textures (i.e., textures not designed to be repeated).

That is how a resource library lookup works - you give it a set of criteria, and it returns the matches -- osgEarth then randomly selects one of the results. Refer to this topic for more information on skin selection criteria.


back to docs