BabylonJS and Blazor - Importing Meshes
For this article we will go over Importing Meshes implemented in C#, this article will go over the process of importing glTF models. Checkout the What Changed section, as one of the interesting areas was what changed to accommodate better performance of ground detection.
Checkout BabylonJS and Blazor - Lanterns, the next step in the series!
Demo and Source Code
Below is a demo of the Blazor application after Step 7 is implemented, you can open the demo in a new tab by going to BabylonJS Blazor Step 07.
Use the Arrow keys to move the around the map. Space key to Jump and the Shift key to Dash while in the Air.
You can see the full source code in GitHub: canhorn/BabylonJS.Blazor.Game.Tutorial at step/07_Importing-Meshes
If you want to see the original step in the Series: Importing Meshes | Babylon.js Documentation (babylonjs.com)
With this step we remove the old
MeshBuilder created Mesh objects and replace them with
SceneLoader loaded Mesh objects. By using the
SceneLoader we are able to take a fully built out Mesh Environment and load it into our Game. By using glTF, Graphics Language Transmission Format, asset files for our models we get a few advantages by using it with BabylonJS. The glTF Model format is a supported format for BabylonJS and if using the non-binary version you can see the structure of the model in plain text.
Not much else was done in this Step so we only have a few places updated to use the
SceneLoader. I also uploaded all the asset files to the wwwroot folder, these will be used in the future articles. This gives the game a very nice polished look, it still has a few features left to implement but this is a large step in the direction of a finished Game.
One area that needed changing, compared to how it was done with TypeScript, was in how the Player calculated if the mesh was on the ground or not. The calculation for gravity to the Player and if they are able to Dash needs to know if the state of the Player. The change was to the Ray check and the predicate, the predicate is used to check if a model is visible or not.
The Ray cast in in the down direction to the Player model, this uses a callback/predicate to check each mesh it was hit. The hit check problem causes a performance hit passing through the Blazor interop layer. This layer is performant enough for most scenarios but not performant enough when it has to happen 50 plus times a frame, at 60 frames per second.
The fix was to eliminated the per mesh callback used by the intersection check. The Ray checks
IsVisible by default but the original Tutorial logic uses the
IsVisible to hide meshes that are used for the ground. To get the performance we want, hide specific ground meshes, we set the mesh
IsVisible = true and make the
Visibility = 0 giving us the same results.
The reason to do this is so our Meshes have a consistent and predictable hit box. Some meshes have gaps for ascetics and the Ray has a chance to cast between these gaps. This can cause the Player to get stuck in some in the air, but collision stopping them from moving state. The Ray check against the hidden Ground meshes give the Player a consistently flat area to stand on.
We had one problem area with the Ray checks causing frame dips, making the game hard to play with the way the movement is locked to frames. We were able to work around this issue by removing the interop section of code and implementing the changes stated in the prior What Changed section. This issue was the only one ran into and fixed in this article, and future articles will build on what was done here for more advanced features.
Source Code Example(s)
Below is an example of loading the envSettings.glb file into BabylonJS, and working against the meshes after the glTF is loaded.
private async Task<EnvSettingAsset> LoadAsset()
// Using SceneLoader of BabylonJS we are able
// to load in a fully built out Game environment!
var result = await SceneLoader.ImportMeshAsync(
After the player is loaded we are need to move them to the starting location in Environment, below we are looking for a node by id and using the Absolute Position to position the player model.
// The name on our player mesh
).position = scene.getTransformNodeByID(
// The starting position loaded as part of the environment glTF loading.