-
Notifications
You must be signed in to change notification settings - Fork 292
Viewing BIM Models Offline
See also:
- Viewing Models from BIMServer - loading IFC models from BIMServer
- High-Performance-Model-Representation - high performance scene representation for huge models
- Importing Models - loading models from other formats
xeokit provides two plugins for loading IFC geometry and metadata from the file system:
-
GLTFLoaderPlugin - loads geometry from
.glTF
and IFC metadata from JSON -
XKTLoaderPlugin - loads geometry from
.xkt
format and metadata from JSON
Though loading from different formats, these plugins are virtually functionally identical. In this tutorial, we'll use the GLTFLoaderPlugin, but almost everything in this tutorial can also be done using the XKTLoaderPlugin.
- Example
- Setting Initial States for IFC Types
- Masking what IFC Types are Loaded
- Prioritizing the order in which IFC Types are Loaded
- Creating the Files
Click the image below for a live demo.
We load our IFC model from two files:
- a JSON file containing metadata about each IFC element, and
- a glTF file containing objects with IDs matching the elements in the IFC JSON.
The code snippets below show how it's done. We'll create a Viewer, to which we'll add a GLTFLoaderPlugin, with which we'll load our model:
import {Viewer} from "./../src/viewer/Viewer.js";
import {GLTFLoaderPlugin} from "./../src/plugins/GLTFLoaderPlugin/GLTFLoaderPlugin.js";
// Create a Viewer
const viewer = new Viewer({
canvasId: "myCanvas"
});
// Add a GLTFLoaderPlugin
const gltfLoader = new GLTFLoaderPlugin(viewer);
// Load glTF and metadata
const model = gltfLoader.load({
id: "myModel",
src: "./models/OTCConferenceCenter.gltf",
metaModelSrc: "./models/OTCConferenceCenter.json"
});
// Fit camera to model when loaded
model.on("loaded", function() {
viewer.cameraFlight.jumpTo(model);
});
After loading, the GLTFLoaderPlugin has created Entities to represent our model and its objects, which we can find by ID.
Through the Entity's, we can control the objects, updating their visibilities, enabling effects, querying boundaries, and so on.
We can find our model and object Entities like this:
const theModel = viewer.scene.models["myModel"];
const anObject = viewer.scene.objects["3NI6Sp$yf87eKCx0T$FWj3"];
Let's update the state of our model and one of its objects:
// Controlling model visibility
theModel.visibility = false;
theModel.visibility = true;
// Controlling object visibility
myObject.visibility = false;
myObject.visibility = true;
// Highlight an object
myObject.highlighted = true;
// Get an object's axis-aligned World-space boundary
const boundary = myObject.aabb;
// Fly camera to an object
viewer.cameraFlight.flyTo(myObject);
The plugin has also created a MetaModel that provides IFC metadata for our model, along with with a MetaObject for each object.
We can get IFC metadata for the model and its objects like this:
// Get matadata on our model
const metaModel = viewer.metaScene.metaModels["myModel"];
// Get metadata on an object
const metaObject = viewer.metaScene.metaObjects["3NI6Sp$yf87eKCx0T$FWj3"];
const name = metaObject.name; // "stelkozijn",
const type = metaObject.type; // "IfcWindow",
const parent = metaObject.parent; // "2SWZMQPyD9pfT9q87pgXa1"
When loading metadata, GLTFLoaderPlugin will also by default apply certain
initial states to objects whose types match known standard IFC types. For example,
setting IfcSpace
types invisible and unpickable, setting IfcWindow
types blue and transparent, etc.
GLTFLoaderPlugin has a default map of these states, but we can override
that as needed to apply our own states. In the example below, our map is
the same as the default, except that we'll set IfcWall
types purple.
The priority
properties are used to set the order in which the objects
load, which we'll explain a couple of sections down.
Click the image below for a live demo.
// Define our own custom initial states for objects
const myObjectDefaults = {
IfcWall: {
colorize: [ 0.537255, 0.537255, 0.837255],
priority: 0
},
IfcRoof: {
colorize: [0.837255, 0.203922, 0.270588],
priority: 0
},
IfcSlab: {
colorize: [0.837255, 0.603922, 0.670588],
priority: 0
},
IfcDoor: {
colorize: [0.637255, 0.603922, 0.670588],
priority: 1
},
IfcStair: {
colorize: [0.637255, 0.603922, 0.670588],
priority: 2
},
IfcColumn: {
colorize: [0.137255, 0.403922, 0.870588],
priority: 3
},
IfcSpace: {
colorize: [0.137255, 0.403922, 0.870588],
pickable: false,
visible: false,
opacity: 0.5,
priority: 3
},
//...
DEFAULT: { // All other types get this color
colorize: [0.5, 0.5, 0.5]
}
};
// Use our custom initial default states for object Entities
const model = gltfLoader.load({
id: "myModel",
src: "./models/gltf/duplex/scene.gltf",
metaModelSrc: "./metaModels/duplex/metaModel.json",
objectDefaults: myObjectDefaults
});
We can optionally load only those objects that have the specified IFC types. In the example below, we'll load only the objects that represent walls, in order to create a plan view.
Click the image below for a live demo.
const model = gltfLoader.load({
id: "myModel",
src: "./models/gltf/OTCConferenceCenter/scene.gltf",
metaModelSrc: "./metaModels/OTCConferenceCenter/metaModel.json",
includeTypes: ["IfcWallStandardCase"]
});
We can also optionally load only those objects that do not have the specified IFC types. In the example below, we'll load only the objects that do not represent empty spaces.
const model = gltfLoader.load({
id: "myModel",
src: "./models/gltf/OTCConferenceCenter/scene.gltf",
metaModelSrc: "./metaModels/OTCConferenceCenter/metaModel.json",
excludeTypes: ["IfcSpace"]
});
Notice the priority
properties on the the myObjectStates
map above. That property allows us to set the order in which the GLTFLoaderPlugin
loads objects, based on their IFC types.
In our example, GLTFLoaderPlugin
will load IfcWall
, IfcRoof
and IfcSlab
objects first, begin rendering those, then load IfcStair
objects, then IfcColumn
objects, and so on.
This provides a more interesting user experience, where the user can navigate the most visually interesting objects first, while the less-interesting objects load in the background.
Note that this feature is not supported by XKTLoaderPlugin
.
Potentially, we can generate our glTF and JSON files via some sort of custom automated server-side pipeline.
However, for the purpose of demonstrating xeokit, I used open source CLI tools to convert the IFC into glTF, and my own node.js-based client for BIMServer to generate the JSON metadata. Read more about that in Creating Files for Offline BIM.