Overview
This xeokit SDK v0.5.0 beta release includes: support for larger BIM models, 2D plan views and mini-maps, ability to save and restore viewer state, improved BCF support, plus numerous enhancements and bug fixes. Many thanks to UniZite, BIMData, BIMSpot and D-Studio for helping with this release.
Contents
- Contributors
- Load Large Models Faster
- Storey Plan Views
- Transformable Models
- CLI glTF to XKT Converter
- Picking Enhancements
- Canvas Snapshot Improvements
- Support BCF view_setup_hints
- Save and Restore Viewer State
- Settable CameraControl 3D Pivot Position
- NavCube Enhancements
- Enable backface culling by default
- These links don't work in GitHub release pages
Contributors
Special thanks to:
- Hugo Duroux, at BIMData
- Gaëtan Lagier at BIMData
- Toni Marti at UniZite
- Adam Eri at BIMSpot
- Barnabas Molnar at BIMSpot
- tothatt81
- D-Studio for sponsoring various features and fixes
Load Large Models Faster
Geometry Reuse in .XKT Format
xeokit's compressed binary .XKT
model format is now even more efficient to load and render, thanks to the efforts of Toni Marti at UniZite.
We're calling this .XKT
format V2. The xeokit-gltf-to-xkt conversion tool and XKTLoaderPlugin are also updated to support .XKT
V2.
To achieve this performance improvement, Toni extended the .XKT
format to reuse geometries within the model. A case where we would reuse geometries is the windows in a building, where we would have a single geometry representing the shape of a window, which is reused by all the window objects.
This has several benefits:
- reduces file size, making models load faster,
- consumes less browser and GPU memory, allowing bigger models,
- consumes less GPU bandwidth, and
- renders more efficiently using WebGL hardware instancing.
The table below shows the reductions in file size, time to convert from glTF, and loading time:
Storey Plan Views
The new StoreyPlansPlugin provides a flexible set of building blocks with which we can build a variety of UX for navigating the storeys within our BIM models.
The plugin supports most of the UX flavors found in existing BIM viewers. There are two general flavors:
- navigate plan views within the main viewer canvas (usually 2D orthographic), and
- interactive mini-maps to help us navigate storeys in the viewer canvas (usually in first-person mode).
2D Plan Views
We can use StoreyViewsPlugin to set up views (often orthographic plan views) of building storeys within the main 3D view.
Mini-maps
We can also use StoreyViewsPlugin to generate mini-maps that you can use to track your current position within a storey, or fly to the location you click on.
Transformable Models
We can now rotate, scale and translate .xkt
and glTF models as we load them. This lets us load multiple models, or even multiple copies of the same model, and position them apart from each other.
Previously, GLTFLoaderPlugin only supported these transformations when configured with performance:false
.
import {Viewer} from "../src/viewer/Viewer.js";
import {XKTLoaderPlugin} from "../src/plugins/XKTLoaderPlugin/XKTLoaderPlugin.js";
const viewer = new Viewer({
canvasId: "myCanvas"
});
viewer.camera.eye = [-5.13, 16.83, 39.46];
viewer.camera.look = [22.20, 1.86, 4.44];
viewer.camera.up = [0.19, 0.94, -0.25];
const xktLoader = new XKTLoaderPlugin(viewer);
var i = 0;
xktLoader.load({
src: "./models/xkt/duplex/duplex.xkt",
metaModelSrc: "./metaModels/duplex/metaModel.json",
edges: true,
scale: [0.5, 0.5, 0.5],
position: [i++ * 10, 0, 0]
})
.on("loaded", () => {
xktLoader.load({
src: "./models/xkt/duplex/duplex.xkt",
metaModelSrc: "./metaModels/duplex/metaModel.json",
edges: true,
scale: [0.5, 0.5, 0.5],
position: [i++ * 10, 0, 0]
})
.on("loaded", () => {
xktLoader.load({
src: "./models/xkt/duplex/duplex.xkt",
metaModelSrc: "./metaModels/duplex/metaModel.json",
edges: true,
scale: [0.5, 0.5, 0.5],
position: [i++ * 10, 0, 0]
})
.on("loaded", () => {
xktLoader.load({
src: "./models/xkt/duplex/duplex.xkt",
metaModelSrc:
"./metaModels/duplex/metaModel.json",
edges: true,
scale: [0.5, 0.5, 0.5],
position: [i++ * 10, 0, 0]
})
.on("loaded", () => {
xktLoader.load({
src: "./models/xkt/duplex/duplex.xkt",
metaModelSrc:
"./metaModels/duplex/metaModel.json",
edges: true,
scale: [0.5, 0.5, 0.5],
position: [i++ * 10, 0, 0]
});
});
});
});
});
CLI glTF to XKT Converter
The xeokit-gltf-to-xkt conversion tool can now be run from the command line, thanks to Hugo Duroux at BIMData.
This means that we can now use scripts to fully automate the conversion of IFC, COLLADA and glTF models to xeokit's optimized binary .xkt
format
Picking Enhancements
Picking is where we select objects, either at given canvas coordinates or with an arbitrarily-positioned 3D ray. This release supports two more options for picking:
- option to pick invisible entities, and
- option to provide a matrix when ray-picking, as an alternative way to indicate the ray.
In the example below, we'll pick whatever Entity intersects the given ray, even if the Entity is currently invisible:
const pickResult = myViewer.scene.pick({
pickInvisible: true, // Picking both visible and invisible Entitys
origin: [10,10,10],
dir: [-10, -10, -10]
});
if (pickResult) { // Picked an Entity with the ray
// ....
}
In the second example, we'll pick the Entity that intersects a ray, which we'll implicitely provide as a 4x4 matrix:
const pickMatrix = math.lookAtMat4v([0,10,0], [0,-1,0], [0,0,-1]); // Eye, look and up vectors
const pickResult = myViewer.scene.pick({
pickMatrix: pickMatrix
});
if (pickResult) { // Picked an Entity with the ray
// ....
}
Canvas Snapshot Improvements
When taking a canvas snapshot, xeokit now 1) temporarily resizes the canvas to the target width and height, 2) takes the snapshot, then 3) restores the canvas size. This allows us to take snapshots that have a different aspect ratio to the canvas, and also improves their sharpness, since xeokit no longer needs to scale the captured image to the target width and height.
For example, to take a square snapshot of a panorama-shaped canvas:
const imageData = viewer.getSnapshot({
format: "png",
width: 200,
height: 200
});
Support BCF view_setup_hints
BCFViewpointsPlugin
now saves and loads view_setup_hints
in BCF viewpoints.
When saving a viewpoint, we can selectively save properties into view_setup_hints
like this:
const bcfViewpoints = new BCFViewpintsPlugin(viewer);
const viewpoint = bcfViewpoints.getViewpoint({ // Options
spacesVisible: false, // Don't force IfcSpace types visible in viewpoint (default)
spaceBoundariesVisible: false, // Don't show IfcSpace boundaries in viewpoint (default)
openingsVisible: false // Don't force IfcOpening types visible in viewpoint (default)
});
When loading a viewpoint, BCFViewpointplugin
will load those properties if they are found in the viewpoint.
Save and Restore Viewer State
New memento classes allow us to save and restore the state of the Viewer. These are useful when we need to temporarily switch to some view of our model, then switch back to the previous view when finished.
The StoreyViewsPlugin (see above) uses these mementos to transition to and from isolated views of building storeys. When switching to an isolated view, the plugin first saves the current camera and object states to mementos before showing the view. When the user wants to transition back to the previous view, StoreyViewsPlugin then restores the camera and objects from the mementos.
There are two memento classes: CameraMemento and ObjectsMemento.
CameraMemento
In the example below, we'll create a Viewer and use an XKTLoaderPlugin to load a .xkt
model. When the model has loaded, we'll save a snapshot of the Camera state in a CameraMemento. Then we'll move the Camera, and then we'll restore its original state again from the CameraMemento.
import {Viewer} from "../src/viewer/Viewer.js";
import {CameraMemento} from "../src/scene/mementos/CameraMemento.js";
const viewer = new Viewer({
canvasId: "myCanvas"
});
// Load a model
const xktLoader = new XKTLoaderPlugin(viewer);
const model = xktLoader.load({
id: "myModel",
src: "./models/xkt/schependomlaan/schependomlaan.xkt"
});
// Set camera
viewer.camera.eye = [-2.56, 8.38, 8.27];
viewer.camera.look = [13.44, 3.31, -14.83];
viewer.camera.up = [0.10, 0.98, -0.14];
model.on("loaded", () => {
// Model has loaded
// Save memento of camera state
const cameraMemento = new CameraMemento();
cameraMemento.saveCamera(viewer.scene);
// Move the camera
viewer.camera.eye = [45.3, 2.00, 5.13];
viewer.camera.look = [0.0, 5.5, 10.0];
viewer.camera.up = [0.10, 0.98, -0.14];
// Restore the camera state again
objectsMemento.restoreCamera(viewer.scene);
});
ObjectsMemento
In the example below, we'll create a Viewer and use an XKTLoaderPlugin to load an .xkt
model. When the model has loaded, we'll hide a couple of Entitys and save a snapshot of the visual states of all the Entitys in an ObjectsMemento. Then we'll show all the Entitys again, and then we'll restore the visual states of all the Entitys again from the ObjectsMemento, which will hide those two Entitys again.
import {Viewer} from "../src/viewer/Viewer.js";
import {ObjectsMemento} from "../src/scene/mementos/ObjectsMemento.js";
const viewer = new Viewer({
canvasId: "myCanvas"
});
// Load a model
const xktLoader = new XKTLoaderPlugin(viewer);
const model = xktLoader.load({
id: "myModel",
src: "./models/xkt/schependomlaan/schependomlaan.xkt"
});
model.on("loaded", () => {
// Model has loaded
// Hide a couple of objects
viewer.scene.objects["0u4wgLe6n0ABVaiXyikbkA"].visible = false;
viewer.scene.objects["3u4wgLe3n0AXVaiXyikbYO"].visible = false;
// Save memento of all object states, which includes those two hidden objects
const objectsMemento = new ObjectsMemento();
objectsMemento.saveObjects(viewer.scene);
// Show all objects
viewer.scene.setObjectsVisible(viewer.scene.objectIds, true);
// Restore the objects states again, which involves hiding those two objects again
objectsMemento.restoreObjects(viewer.scene);
});
Settable CameraControl 3D Pivot Position
So we can do things like automatically pivot about the center of the whole scene:
const aabb = myViewer.scene.getAABB(myViewer.scene.visibleObjectIds);
myViewer.cameraFlight.flyTo({
aabb: aabb
});
myViewer.cameraControl.pivotPos = math.getAABB3Center(aabb, math.vec3());
NavCube Enhancements
Option for NavCube to view-fit to visible objects only
NavCubePlugin now supports the option to fit the axis, corner and edge-aligned views to visible object-Entitys only.
const navCube = new NavCubePlugin(viewer, {
canvasID: "myNavCubeCanvas",
//...
fitVisible: true
});
Customizable NavCube Colors
NavCubePlugin now supports custom colors:
new NavCubePlugin(viewer, {
//...
// Custom color configurations
// We can optionally supply a uniform color for the whole cube:
color: "#99FF99", // Default value
// We can also optionally supply a separate color per face,
// which will override our uniform color, if we supplied that:
frontColor: "#55FF55", // Default values
backColor: "#55FF55",
leftColor: "#FF5555",
rightColor: "#FF5555",
topColor: "#5555FF",
bottomColor: "#5555FF",
// We can also supply a color to highlight NavCube regions
// as we hover the pointer over them:
hoverColor: "rgba(0,0.5,0,0.4)" // Default value
});
Enable backface culling by default
Backface culling is now enabled by default. This means that triangles that are facing away from the Camera not be rendered, unless we configure it. It also means that you'll your triangle meshes will have holes if their triangles have irregular vertex windings.