babylon.js
Integrate babylon.js rendering into ImFusion Web SDK views with a CustomGlObject.
Here we show a simplified version of babylon.js' Area Lights demo, integrated into the SDK's views.
Loading demo…
babylon.js defaults to a left-handed coordinate system, so set the scene to right-handed to match the SDK. It also has no single "reset GL state" call, so we reset its caches and gl.CULL_FACE each frame.
ts
const gl = imf.canvas.getContext('webgl2')!;
// ThinEngine's constructor calls resize(), which overwrites canvas.width/height,
// so capture the SDK's drawing-buffer size and restore it afterwards.
const bufferWidth = imf.canvas.width;
const bufferHeight = imf.canvas.height;
const engine = new ThinEngine(gl, true, { preserveDrawingBuffer: true }, false);
imf.canvas.width = bufferWidth;
imf.canvas.height = bufferHeight;
const scene = new Scene(engine);
scene.autoClear = false;
scene.useRightHandedSystem = true;
// Reset GL state
engine.wipeCaches(true);
gl.disable(gl.CULL_FACE);In render, map the SDK matrices to the camera:
ts
// Here you would compute an axis aligned bounding box of your CustomGlObject in world space.
// This information is used by the ImFusion Web SDK to compute bounds for the whole rendered scene
// and corresponding clipping planes. For demo purposes we return invalid bounds, which tells the
// ImFusion Web SDK to ignore this CustomGlObject in those computations.
const bounds = new imf.bindings.AlignedBox();
const babylonGlObject = {
render: (viewState: GlViewState) => {
// babylon.js viewports are normalized to [0, 1]
const imfViewport = viewState.viewport();
camera.viewport = new Viewport(
imfViewport.x / imf.canvas.width,
imfViewport.y / imf.canvas.height,
imfViewport.width / imf.canvas.width,
imfViewport.height / imf.canvas.height,
);
// Transpose for the row-major vs column-major difference in matrix storage.
// Invert to get viewToWorld from the worldToView matrix the SDK provides.
const modelViewMatrix = Matrix.FromArray(viewState.modelViewMatrix()).transpose().invert();
const scale = Vector3.Zero();
const translation = Vector3.Zero();
const quaternion = Quaternion.Zero();
modelViewMatrix.decompose(scale, quaternion, translation);
camera.position = translation;
camera.rotationQuaternion = quaternion;
const projectionMatrix = Matrix.FromArray(viewState.projectionMatrix()).transpose();
camera.freezeProjectionMatrix(projectionMatrix);
scene.render(false);
// Reset GL state
engine.wipeCaches(true);
gl.disable(gl.CULL_FACE);
},
bounds: () => bounds,
};
const customGlObject = imf.createCustomGlObject(babylonGlObject, 'glObjectBabylonJS');Add it to the views:
ts
imf.display.mainSagittalView().addObject(customGlObject);
imf.display.main3dView().addObject(customGlObject);