In the first post in this series we looked at how a heatmap can be used to shade an object using the Forge viewer’s Data Visualization Extension – or Project Hyperion. In our case we shaded the surface of the MX3D bridge.
In this post we look at a slightly different use-case for this mechanism, where we want to shade a piece of geometry inside the model based on the value of a particular sensor. To be clear: this is about shading the entire object a uniform colour that varies based on the value of the sensor that’s providing the data. An example of when you might want to do this is to have mechanical devices in the model shaded based on their temperature.
In Dasher we typically have sensor geometry – often instances of a Revit family – stored in the model. When the Forge viewer loads the property data for the model, it looks for our sensor objects with metadata containing a valid sensor ID in our time-series back-end: when we find one we create a sensor located at the centroid of the geometry’s bounding box. This sensor has a connection to the originating geometry (we store its dbId in a property).
So while it doesn’t necessarily make a very visible demonstration of this capability – the sensors are quite small – colouring the sensors themselves was by far the easiest way for us to kick the tyres, to see if we could make use of this mechanism inside Dasher. Here you can see the sensors flickering based on their data:
When I first implemented this, I had all the sensors in a single SurfaceShadingData object, irrespective of their type. It soon became clear that I needed to create a separate shadingData for each type, as having a single one – animating all at the same time – would lead to clashes between the objects being shaded (we have sensors that have feeds for temperature, humidity and CO2, for instance, and the one that won the fight to be shown was typically the last type to be added).
Here’s the overall approach we’ve now implemented:
- Create a SurfaceShadingData object for each sensor type.
- Create a SurfaceShadingGroup object for each shadingData object.
- For each sensor, create a SurfaceShadingNode and a SurfaceShadingPoint.
- Add the shadingPoint to the shadingNode and the shadingNode to the correct shadingGroup for the sensor’s type.
- Set the position of the shadingPoint using the positionFromDBId() method.
- As a post-processing step, initialize the fragIds for the various dbIds in the shadingData.
- Again, this shouldn’t be needed if using Revit models (or Navisworks, for that matter).
- Call setupSurfaceShading(), passing in the shadingData for the type of sensor to visualize.
Here’s how it looks with separate shadingData objects for each sensor type:
We’re thinking about other use-cases for this mechanism, such as shading geometry based on the presence of people in the building. This kind of visualization – alongside the ever-useful Viewer3D.setThemingColor() – has lots of potential to display interesting data.