Vue & BJS - loading glb

Hi There,

Is there anyone with experience using BJS in Vue?
We’re working on a project where we’d like to use this combination.
However I’m stuck on importing a mesh file from the assets folder.

Here you can see the position of the glb assets, and how it’s referenced in the code.

However when previewing the page I get this error:

Any tips on how to resolve this?
Thanks a lot!

Looks like you could be using ES6 version of Babylon, if so, need to include this:

export {} from '@babylonjs/loaders/glTF' // enable gltf/glb file support
1 Like

Thanks for your reply,

To give a bit more context about my setup.
I’m using the starter template vitesse
Using Vue 3, Vite 2, pnpm, ESBuild among other elements.

I found a similar topic about this, however there webpack is used.
There i’ve added some details as well about my issue

Thanks!

I also solved this but with regular vue and webpack Vite does not use webpack I think right? . In the end im sure vite has to be doing some bundling? bundling is part of modern build tools. So in some way the reference to the build time assets in the assets directory in your code would need to be updated when building to point to the assets which would have been bundled themselves copied/created into some dist folder?

True, in the end the files should be bundled but also during development it would be appreaciated to be able to view the files present and used in the code. Like images, and models.
And Vite doesn’t use webpack, you’re right so it might be slightly different here.

I also found this thread which was interesting. At first I didn’t also add a line to import a gltf loader as a module. Without this I also couldn’t load an asset from a remote web location.

With import { GLTFLoader } from '@babylonjs/loaders/glTF/2.0/glTFLoader'
This does work. But only for an online resource.

My local glb model saved under the src/assets/ is still not loading.
But the issue seems to occur before loading the model with the import of the model as module: Cannot find module './../assets/EPSI.glb' or its corresponding type declarations.ts(2307)

So… This doens’t work:

mat.diffuseTexture = new Texture('./../assets/ECLogo.png')

But this does:

import textFile from './../assets/ECLogo.png'
...
mat.diffuseTexture = new Texture(textFile)

In the same assets folder I have a EPSI.glb model file.
But when importing the model on top of the code, ts throws a warning and says that the module can’t be found. This makes it strange, the *.png can be loaded, but the *.glb not.

import model from './../assets/EPSI.glb'

Resulting that model with Append can’t be loaded:

SceneLoader.Append('', model, scene, model => log(model))

Hi, you might try it without the leading . to see if it works as “/assets”.

Or maybe this is a file extension issue with Vite and you need to add .glb here …
Configuring Vite | Vite (vitejs.dev)

yes from what @Pieter_van_Stee says it seems it is simply the same issue of the bundler ( whatever vite uses or webpack ) not handling custom objects by default and requiring some config.

1 Like

Thanks for your feedback.

At the moment I tried your suggestion to add the assetsInclude option to the vite config file.
However this couldn’t help unfortunately.

export default defineConfig({
  resolve: {
    alias: {
      '~/': `${path.resolve(__dirname, 'src')}/`,
    },
  },
  assetsInclude: ['**/*.gltf', '**/*.glb'],
  plugins: [
  ...

This is the code I have for testing purposes:

<script setup  lang="ts">
import {
  ArcRotateCamera,
  Engine,
  HemisphericLight,
  Mesh,
  MeshBuilder,
  Scene,
  SceneLoader,
  StandardMaterial,
  Texture,
  Vector3,
  Vector4,
} from '@babylonjs/core'
import '@babylonjs/loaders/glTF'
import { GLTFLoader } from '@babylonjs/loaders/glTF/2.0/glTFLoader'

import model from './../assets/EPSI.glb'
import textFile from './../assets/EpsilonCitiesLogo.png'

const router = useRouter()
const { t } = useI18n()

const cnvs = ref(null)

const log = (object: any) => {
  console.log(object) // eslint-disable-line no-console
}
log('cnvs started')

const setupRenderLoop = (engine: Engine, scene: Scene) => {
  engine.runRenderLoop(() => {
    scene.render()
  })
}

const createScene = (scene: Scene, canvas: HTMLBodyElement) => {
  const camera = new ArcRotateCamera('Camera', -Math.PI / 2, Math.PI / 2, 3, Vector3.Zero())
  camera.attachControl(canvas, true)
  const light = new HemisphericLight('light', new Vector3(1, 1, 0), scene)

  const f = new Vector4(0, 0, 0.5, 1) // front image = half the whole image along the width
  const b = new Vector4(0.5, 0, 1, 1) // back image = second half along the width
  const mat = new StandardMaterial('')
  mat.diffuseTexture = new Texture(textFile)

  // const plane = MeshBuilder.CreatePlane('plane', { frontUVs: f, backUVs: b, sideOrientation: Mesh.DOUBLESIDE })
  // plane.material = mat
  // SceneLoader.Append('', model, scene, model => log(model))
  SceneLoader.Append('', './../assets/EPSI.glb', scene, model => log(model))
  SceneLoader.ImportMesh(
    '',
    'https://raw.githubusercontent.com/BabylonJS/MeshesLibrary/master/',
    'PBR_Spheres.glb',
    scene,
    (meshes) => {
      scene.createDefaultCameraOrLight(true, true, true)
      scene.createDefaultEnvironment()
    })
  // SceneLoader.ImportMesh('', 'https://babylon.sfo3.digitaloceanspaces.com/', 'gifts.glb', scene, model => log(model))
}

onMounted(() => {
  const engine = new Engine(cnvs.value)
  const scene = new Scene(engine)

  const resize = () => {
    engine.resize()
  }

  window.addEventListener('resize', resize)

  createScene(scene, cnvs.value!)
  setupRenderLoop(engine, scene)
})

</script>

<template>
  <p>CNVS Viewport</p>
  <div>
    <button
      btn m="3 t6" text-sm
      @click="router.back()"
    >
      {{ t('button.back') }}
    </button>
  </div>
  <canvas ref="cnvs" class="absolute top-0 h-screen w-full !outline-none bg-rose-300" />
  <img src="./../assets/EpsilonCitiesLogo.png" class="inline-block py-10 z-50" alt="">
  <nav-chapter />
</template>

Giving me the following:

So you can see the external asset is properly being loaded.
But as @westonsoftware mentioned the glb seems to be omitted?
Also my ts gives this as an error:

And my autocomplete path intellisense indicates the file is there to be sure there is no mistake in file path. Also the model works correctly when exported through the bjs exporter in 3Ds Max, it loads in the bjs sandbox without any issue.

Thanks again

Ok, found it now… :tada:
This thread on stack overflow did the trick…

I had to add ?url using explicit url import like so:

import model from './../assets/EPSI.glb?url'

Thanks for the support everyone!

3 Likes

Thanks, it helped me !

same problem, my trick was to put the assets in the public folder (same than index.html) and call the files via
“./”, “model.glb”

Glad to see a better solution :wink:

1 Like

This was driving me crazy. @Boz, thank you! I don’t know yet if that’s best practice, but that works for my project. :+1:

I structure the project tree and asset this way…

public

assets

cube.glb

Then used this code…
SceneLoader.Append("assets/", "cube.glb", scene, function (scene) {});

logger.ts:103 BJS - [22:56:03]: Unable to find a plugin to load .glb files. Trying to use .babylon default plugin. To load from a specific filetype (eg. gltf) see: Loading Any File Type | Babylon.js Documentation

I reread this thread few times, but don’t understand how you resolve this issue?

import '@babylonjs/loaders/glTF';
import { GLTFLoader } from '@babylonjs/loaders/glTF/2.0/glTFLoader';
import Crystal1 from '@/entities/Game/envirement/crystals/Crystal.glb?url';

// ...
const data = SceneLoader.ImportMeshAsync('Cry', Crystal1);

Where result:
sceneLoader.ts:761 Uncaught (in promise) RuntimeError: Unable to load from /src/entities/Game/envirement/crystals/Crystal.glb: importMesh of undefined from undefined version: undefined, exporter version: undefinedimportMesh has failed JSON parse