Adding Different Textures to a 3D City Model

Liz Sanderson
Liz Sanderson
  • Updated

FME Version

  • FME 2018.x


This article is designed to give an overview of FME's 3D capabilities by leading you through an extended exercise to work with a 3D city model.

In this example, we will work with an Autodesk 3DS model of a city to add separate textures to the roofs and the walls, allowing for more realistic viewing. We will write out this model to 3D PDF for viewing.


Step-by-step Instructions

1. Read Autodesk 3ds Source Data

The Interopolis 3D model is a simple Autodesk 3DS model of a small section of downtown.

Select interopolis.3ds as your source Dataset. In the Parameters window, make sure that ‘Move to World Coordinate System’ is set to yes. This will cause FME to read the .wld and .prj files and move our city model to Texas State Plane.


The source 3DS model viewed in the FME Data Inspector.

2. Disaggregate the Single Mesh

This model has a single feature containing every building in a single mesh, we need to separate the buildings into their own features so that we can give each building an ID for our final CityGML. Add the Deaggregator transformer to break down the mesh into its aggregates.

3. Count the Buildings

Set the Count Output Attribute to ‘BuildingID’ using the Counter. This will give each building an ID number. We will need to further deaggregate our features before we can apply textures, and the ID numbers will help us put them back together later.

4. Convert Buildings into MultiSurface Geometries

Use the GeometryCoercer to set the Geometry Type to ‘fme_composite_surface’. A Mesh geometry consists of a single surface, and will not meet our needs, as we have separate textures for our roofs and walls. We can use the GeometryCoercer to convert our buildings into MultiSurface geometries, which consist of several faces aggregated into a single feature.

5. Deaggregate the MultiSurfaces

Now that the buildings are comprised of multiple faces, we can deaggreate the MutliSurfaces with the Deaggregator into individual features and set different appearances for different parts of the building.

Be sure to set ‘Split Composites’ and ‘Explode Instances’ to Yes to create individual solids from each composite solid.


This step is important for the next step so that we can filter features through the Planar port in the PlanarityFilter. For a feature to be planar, a geometry must have all its points situated on the same plane, so we need to split composites and explode instances to create these planes.

6. Separate the Roofs from the Walls

Next, we need to separate the roofs from the walls to apply separate textures to them. We can do this by using the PlanarityFilter to compute surface normals and then the TestFilter to filter out the roofs and the walls based on those surface normals.

6.1 Compute Surface Normals

In the PlanarityFilter, select ‘Surface Normal Output’ and set ‘Expose Surface Normal’ to Yes. This will expose the surface normal attribute for Z (_surfaceNormalZ) that we will need to filter for in order to differentiate the roof surfaces and the walls in the next step. Luckily this neighborhood does not have peaked roofs!


6.2 Filter out the Roofs and the Walls

Next in the TestFilter transformer, we will use the surface normals to determine whether the face is a wall or a roof. Generally, a wall should have a _surfaceNormalZ of 0, a roof should have a _surfaceNormalZ of 1, and the ground, a _surfaceNormalZ of -1. However, since we don’t have a base surface for the buildings (they are like open upside-down boxes), we want everything that is not a wall to be the roof. So we will use the parameters in the table below:


  Test Condition Output Port
If _surfaceNormalZ > 1e-5
_surfaceNormalZ < -1e-5
Else <All Other Conditions> Wall



When entering in the test conditions, for the Left Value, you can use the down arrow, and select the Attribute Value: ‘_surfaceNormalZ’.



The test conditions for the Output Port: Roof.


7. Add Two Textures Using Two JPEG Files

7.1 Add a JPEG file for the roofs:

Now we need to bring the textures into the workspace. Select one of the three roof textures as your source dataset and add the first JPEG reader to your workspace.

7.2 Add a JPEG file for the walls:

For the second JPEG reader, we want to bring in wall textures. Pick one of the three images for wall textures in the source data.

8. Add the Textures to the Walls and the Roofs

We will use two AppearanceSetters to add an appearance, or raster texture, to the roofs and to the walls respectively.

Connect the Roof texture, the JPEG roof feature type, to the APPEARANCE port of the AppearanceSetter, and the ROOF port from the TestFilter to the GEOMETRY port of the AppearanceSetter. In other words, the AppearanceSetter for the roof is informed by the geometry of the roof, and the appearance of the roof texture.

Do the same thing for the walls. Connect the JPEG wall feature type to the Appearance port, and the Wall port of the TestFilter to the Geometry port of the AppearanceSetter.


Adding textures to the roofs and the walls should look something like this.


9. Aggregate the Features

Now that we have applied the appearances to each surface, we want to merge the surfaces together so that we have a single feature per building again. We will do this with the Aggregator transformer, and setting the ‘Group By’ to ‘BuidlingID’.

10. Set the Geometry Type to Composite Surface for Faster Processing

Using the GeometryCoercer, set the ‘Geometry Type’ to ‘fme_composite_surface’. We currently have a multi-surface geometry, which is easy to work within FME, since we can break it down into individual faces that can be manipulated, but it can be somewhat slow to work with, especially when writing to certain formats. By changing the geometry type to a composite_surface, we let 3D writers know that they can process each multi-surface in a single transaction, rather than processing each surface in a separate transaction.

11. Write Out to 3D PDF

Add the 3D PDF reader and set the output location and file name, then run the translation. If you wish to run the translation more than once, remember to close your PDF output between runs.


Completed Workspace




Congratulations! You have successfully converted a 3DS city model of Interopolis, added a separate roof and wall textures, and written out a 3D PDF.


Here is one possible output, using roof texture 3, and wall texture 1 in 3D PDF.


Here is a close up of a different wall texture (texture 3) in 3D PDF.


Data Attribution

Data used in this article originates from open data made available by the City of Austin, Texas. It contains data licensed under the Public Domain Dedication License - City of Austin.

Was this article helpful?



Please sign in to leave a comment.