glTF loading in gatsby

So I’m kinda tiring of this particular site generator, and going more vanilla, less bloated, but I’ve had this around for a while and would like to see if I can get it working again. I posted in the gatsby github discussion, but it may as well be something I’m doing wrong with babylonjs.

I had starter in a previous version of gatsby where i was able to load a .glb file from a static folder, using the imported BabylonJS loaders. I didn’t have to import the glb into the file at that point- the relative url from the static folder (/) just went in the import function and it loaded. I am trying it in a new starter, newer version of gatsby, and It wont load from static anymore, and none of my attempts to import it in the js file are successful. I have the loader package installed, and using import exactly the same way as I did before.

import * as BABYLON from '@babylonjs/core'; 
import "@babylonjs/loaders/glTF"; 
import backgroundImage from "../assets/shanghai-bund.jpg"; 
import car from "../assets/Renault_Alpine_blendswap_cc0.glb";

now if i comment out that last line with “import car”, the scene loads with just the babylon js primitives, ground and photodome for the background. So there’s nothing wrong with my path, or babylonJS itself loading.
When I uncomment that import car line again, I get the following error, and the server stops:

ModuleParseError: Module parse failed: Unexpected character '' (1:4) You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders (Source code omitted for this binary file)

ok well now obviously I need the loader. but it’s imported as shown above, and of course the package is installed. There is another thread here I saw where this is essentially what is shown. Here is my repo on github, if anyone’s interested. I wish i could set up a better playground scene. I tried playcode but had trouble with dependencies.

I’ve tried different ways of importing. Append, using Asset Manager, and loadFromMemory. Load from memory takes the whole URL, so I thought that might help, but maybe I’m missing something there. But even with all the import code commented out, the import line still throws an error. But here are the ones i’ve alternately tried, (uncommenting one at a time). I’ve also tried putting them in the SceneComponent file, just to see. But i shouldn’t really have to do that, and it had no effect.

    //IMPORT USING APPEND
    // BABYLON.SceneLoader.Append(
    //     "../assets/", 
    //     "Renault_Alpine_blendswap_cc0.glb", 
    //     scene, 
    //     null
    // )


    // TRYING TO IMPORT WTIH ASSET MANAGER
    // const assetsManager = new BABYLON.AssetsManager(scene);
    // const meshTask = assetsManager.addMeshTask("car task", "", "../assets/", "Renault_Alpine_blendswap_cc0.glb");
    // meshTask.onSuccess = function (task) {
    //     task.loadedMeshes[0].position = BABYLON.Vector3.Zero();
    // }	
    // assetsManager.load();


    //TRYING TO LOAD FROM MEMORY
    // async function loadFromMemory (){
    //     const assetArrayBuffer = await BABYLON.Tools.LoadFileAsync(car, true);
    //     //loading from the static folder doesn't work anymore either
    //     const assetArrayBuffer = await BABYLON.Tools.LoadFileAsync("/Renault_Alpine_blendswap_cc0.glb", true);
    //     const assetBlob = new Blob([assetArrayBuffer]);
    //     const assetUrl = URL.createObjectURL(assetBlob);
    //     await BABYLON.SceneLoader.AppendAsync(assetUrl, undefined, scene, undefined, ".glb");
    // }
    // loadFromMemory();

If this doesn’t work, I’m going to scrap it and build around Brian Zinn’s create-react-app implementation. I’m creating repos of as many different JS frameworks as I can get to, to demo use of BJS

cc @RaananW who might know about gatsby

Gatsby is using webpack to bundle and react under the hood (and correct me if I am wrong :slight_smile: ). So usin gthe knowledge for both of those would be very helpful.

Reading your post it seems like you are trying to import a .glb file and webpack is complaining that you don’t have a loader for it. a glb is just like a jpg or any other binary file - you can use the file loader or URL loader to generate a URL that can be used to load the asset. You will need to add something similar to your webpack config:

 {
                test: /\.(png|jpg|gif|env|glb|gltf|stl)$/i,
                use: [
                    {
                        loader: "url-loader",
                        options: {
                            limit: 8192,
                        },
                    },
                ],
            },
3 Likes

Yeah I’ve kinda neglected understanding webpack…I’ll research and come back to this. tbc…

1 Like

I figured it out!

so Webpack is configured within gatsby in a root level file called “gatsby-node.js”. Most starters should have this generated already, or it can be added. what I added was this:

exports.onCreateWebpackConfig = ({
  actions
}) => {
  actions.setWebpackConfig({
    module: {
      rules: [
        {
          test: /\.(glb|gltf)$/i,
          use: {
            loader: "url-loader",
            options: {
              limit: 8192,
            },
          }
        },
      ]
    }
  })
}

There are other parameters for onCreateWebpackConfig, other than “actions”, but they aren’t being used in this context. Also, I limited the file types to just glb and gltf, within the regex, because specifying jpg was interfering with the photodome I have in the scene.

In the onSceneReady function within the component code, I have the glb imported at the top of the file:

import car from "../assets/Renault_Alpine_blendswap_cc0.glb";

and I’m using the loadfromMemory method to import the object, so that the file name doesn’t need to be separated from the path:

    async function loadFromMemory (){
        const assetArrayBuffer = await BABYLON.Tools.LoadFileAsync(car, true);
        const assetBlob = new Blob([assetArrayBuffer]);
        const assetUrl = URL.createObjectURL(assetBlob);
        await BABYLON.SceneLoader.AppendAsync(assetUrl, undefined, scene, undefined, ".glb");
    }
    loadFromMemory();

Below that, the loaded mesh can be accessed and transformed within the resolved function in “.then” for the returned promise

    loadFromMemory().then(
        ()=>{
            const loadedCar = scene.getMeshByName("__root__");
            loadedCar.position.x += 14;
        }
    );

My repo for this is here:
a link to a repo in github

I gotta say, I really love these “get…” methods on the scene object. I dont know how many times I’ve used them in all this.

can I be a Jedi knight now… :slight_smile:

1 Like