Import Models & Assets in WebXR with Babylon.js

Taikonauten
Taikonauten  Magazine
3 min readFeb 13, 2024

👀 Stumbled here on accident? Start with the introduction!

Welcome back to the 8th installment in our WebXR with Babylon.js series. This part is about importing an asset in the form of a 3D model of a door that gets attached to an anchor.

ℹ️ Remember — you can always run the code associated with this article and follow along using npm start --part=8

loading and attaching a model to an anchor
loading and attaching a model to an anchor

Prerequisite

To be able to load model files in the form of assets into a scene we first need to import the Babylonjs model loader for glb/glTF files.

import '@babylonjs/loaders/glTF';

The provided 3D model file consists of 3 layers. A Handle, a Door and a Door_frame.

The loader itself adds a parent node called __root__ to the whole model, therefore the 3 layers are stored as sub-meshes to the __root__.

enum DoorMeshes {
Handle = 'Handle',
Door = 'Door',
DoorFrame = 'Door_frame',
Container = '__root__',
}

To make things easier when loading parts on their own, we create an enum for the layer names.

Loading the model

addDoor(): void {
SceneLoader.Append("/models/", "door.glb", this._scene, ((scene: Scene) => {

this._handle = scene.getMeshByName(DoorMeshes.Handle);
this._door = scene.getMeshByName(DoorMeshes.Door);
this._doorFrame = scene.getMeshByName(DoorMeshes.DoorFrame);
this._doorContainer = scene.getMeshByName(DoorMeshes.Container);

const meshes = this._doorContainer!.getChildMeshes();

meshes.forEach((mesh) => {
this._shadowGenerator!.addShadowCaster(mesh);
mesh.receiveShadows = true;
});

this._handle!.isVisible = false;
this._door!.isVisible = false;
this._doorFrame!.isVisible = false;
}));
}

Next, we’re going to add the addDoor function to load the 3D model in Babylon.js.

SceneLoader.Append loads a model from a specific local file path into the the this._scene.
Once the model is loaded a callback function is called. In the callback function, each mesh is assigned to a variable making them easily accessible later on.

️The most important layer is the node layer which is assigned to this._doorContainer since this is going to be the one that is being attached to an anchor later on.

Then we loop through all the child meshes to:

  • add the mesh as a shadow caster to the this._shadowGenerator, allowing it to cast shadows on the scene
  • setting receiveShadows to true to enable the mesh to receive shadows from other objects in the scene

Finally, we set each mesh to be invisible initially to be later explicitly made them visible again when attached to an anchor.

Adding the door to the scene

async createScene(): Promise<Scene> {
...

this.addDoor();

if (this._xrAnchors && this._xrAnchors.isCompatible()) {
this.observeAnchors();
this.handleControllerSelection();
}

return this._scene;
}

To be able for the scene to load the model, we add this.addDoor() to the createScene function.

Attaching the model to an anchor

addAnchorAtPosition(raycastHit: PickingInfo) {
this._xrAnchors!.addAnchorAtPositionAndRotationAsync(raycastHit.pickedPoint!).then((anchor) => {
const boxTransformNode = new TransformNode('boxTransformNode');

this._box!.parent = boxTransformNode;
this._box!.position = new Vector3(0, 1, .5);
this._box!.isVisible = true;

this._door!.isVisible = true;
this._doorFrame!.isVisible = true;
this._handle!.isVisible = true;

this._doorContainer!.position = raycastHit.pickedPoint!;
boxTransformNode.parent = this._doorContainer!;

anchor.attachedNode = this._doorContainer!;
anchor.attachedNode.position = raycastHit.pickedPoint!;
});
}

Since we already know how to attach a mesh to an anchor, we adjust our previous implementation for the this._box to this._doorContainer. Instead of attaching the this._box directly to the anchor, we assign the this._doorContainer as the parent to the box and assign the doorContainer to anchor.attachedNode. Important in this step is to make the model layers visible by setting isVisible to true.

the final scene in this chapter

Conclusion

In this 8th part, we covered the process of importing and integrating a 3D door model with Babylon.js. We detailed loading the model, managing its components, and attaching it to an anchor. The steps taken demonstrate a straightforward approach to incorporating interactive elements in virtual environments, suggesting practical applications in web technology.

In the eight and final part, we’re going to implement some animations for the door.

--

--

Taikonauten
Taikonauten  Magazine

We Create Digital Products & Services Users Love. Strategy, Concept, Design & Engineering