Unable to load from ./models/dog.glb: importMesh of undefined from undefined version: undefined, exporter version: undefinedimportMesh has failed JSON parse

Hello babylonians,

I’m currently trying to implement my own upload file external assets model by using react typescript and babylonjs.

I have looking through the documentation on Importing your mesh: Importing Meshes | Babylon.js Documentation
when it didn’t work I referred to this part of docs:
Loading Any File Type | Babylon.js Documentation

here is my all code files that are related to what I am trying to accomplish
toolbar.tsx

import { buttonStyles, newProjectBackground, newProjectTitleText,  } from "@/ui/pageSections/NewProject"
import { ToggleSwitch, ToolbarSection, AddModel} from "@/ui/pageSections/Editor"
import { SceneFactory } from "@/scene/SceneFactory";
import { InputModel } from "./MeshSection/InputModel";


export const Toolbar = ({ sceneFactory } : {sceneFactory: SceneFactory | null}) => {
  return (
    <div 
      className="h-full min-w-[300px] py-5 flex flex-col items-center z-10 overflow-y-scroll"
      style={{ background: newProjectBackground.background, boxShadow: newProjectBackground.boxShadow }}
    >
      <div className="flex w-full justify-center items-center border-b border-gray-whisper pb-4 px-4">
        <p className="text-base w-full font-medium font-interMedium tracking-tighter leading-normal text-left" style={{ textShadow: newProjectTitleText.textShadow }}>
          <span className="text-white-default">{"Project "}</span>
          <span 
            style={{
              background: newProjectTitleText.background,
              backgroundClip: newProjectTitleText.backgroundClip,
              WebkitTextFillColor: newProjectTitleText.textFillColor,
              WebkitBackgroundClip: newProjectTitleText.backgroundClip
            }}
          >
            {"Menu"}
          </span>
        </p>
      </div>

      <div className="flex flex-col w-full justify-center items-center divide-y divide-gray-whisper">
        <ToolbarSection title="Meshes">
          <ToggleSwitch title="add ground" cta={ () => sceneFactory!.toggleGround()}></ToggleSwitch>
          <ToggleSwitch title="add sky" cta={ () => sceneFactory!.toggleSky()}></ToggleSwitch>
          <AddModel cta={() => sceneFactory!.addCube()} title={"add cube"} disabled={false}></AddModel>
          <AddModel title={"add shpere"} disabled={true}></AddModel>
          <AddModel  title={"add cylinder"} disabled={true}></AddModel>
          <AddModel title={"add cone"} disabled={true}></AddModel>
           //this code is comment out because I am just trying to importMesh without upload file 
           //instead just using a button
          {/* <InputModel cta = {(file) => sceneFactory!.addModelFromImport(file)}></InputModel> */}
          <AddModel cta={() => sceneFactory!.createPlayerMesh()} title={"Import Model"} disabled={false}></AddModel>
        </ToolbarSection>
        <ToolbarSection title="Lighting">
          <ToggleSwitch title="add hemespheric lighting"></ToggleSwitch>
        </ToolbarSection>
        <ToolbarSection title="Physics"></ToolbarSection>
        <ToolbarSection title="Animations"></ToolbarSection>
      </div>
    </div>
  )
}

InputModel.tsx is a component that I made for upload external model file

import { PlusSmIcon } from "@heroicons/react/solid";
import { buttonStyles } from "@/ui/components/Button"
import React, { useEffect, useRef } from "react";


export const InputModel = ({cta} : {cta: (file: any) => void}) => {
    const fileReader = useRef<FileReader>(new FileReader());
    const reader = fileReader.current;
    useEffect(() => {
        if(reader){
            reader.addEventListener("load", function(){
                cta(reader.result);
                console.log("after readerResult");
            }, false)
        }
    }, [])
   
    const handleUploadFile = (e : React.ChangeEvent<HTMLInputElement> ) => {
        const file = e.target.files;
       
        if(file){
            
            reader.readAsDataURL(file[0]);
           
        }
        
    }
   return(
       <div>
           <input type="file"
            name="inputFile"
            id="input" 
            className={`"opacity-50 pointer-events-none" : "cursor-pointer"} w-auto cta-button flex flex-row justify-center items-center  bg-gray-dark_charcoal rounded border h-min px-2 py-1`}
            onChange={handleUploadFile}
            accept=".glb, .gltf" 
            />
       </div>
   )
}

SceneFactory.ts is where all the code related to Babylon.js

import { 
  Scene,
  Mesh, 
  MeshBuilder, 
  Color3, 
  StandardMaterial, 
  AbstractMesh,
  Size,
  SceneLoader,
} from "@babylonjs/core";
import { SkyMaterial } from "@babylonjs/materials";
import "@babylonjs/loaders/glTF";
export class SceneFactory {
  
  private _scene: Scene;

  

  constructor(scene: Scene) {
    this._scene = scene
  }

  public addCube() : void {
    const cubeMaterial = new StandardMaterial("cubeMat", this._scene)
    cubeMaterial.diffuseColor = Color3.Red()
    const cube = MeshBuilder.CreateBox("new cube", {size: 5}, this._scene)
    cube.material = cubeMaterial
    cube.position.y = 2.5
  }

  

  public toggleGround() : void  {
    const ground = this.getMeshByName("ground")
    if (ground) {
      this.disposeMesh(ground)
      return;
    }

    this.addGround()
  }

  public toggleSky() : void {
    const sky = this.getMeshByName("sky")
    if (sky) {
      this.disposeMesh(sky)
      return
    }

    this.addSky()
  }

  private addGround() : void {
    const groundMaterial = new StandardMaterial("groundMaterial", this._scene)
    groundMaterial.diffuseColor = new Color3(53, 54, 58)
    groundMaterial.alpha = 0.5
    const ground: Mesh = MeshBuilder.CreateGround("ground", {width: 200, height: 200, subdivisions:250}, this._scene)
    ground.material = groundMaterial
  }

  private addSky() : void  {
    const skyMaterial = new SkyMaterial("skyMaterial", this._scene);
    skyMaterial.backFaceCulling = false;
    skyMaterial.turbidity = 1
    const sky = MeshBuilder.CreateBox("sky", {size:200}, this._scene);
    sky.material = skyMaterial;
  }

  private getMeshByName(name: string) : AbstractMesh | undefined {
    return this._scene.meshes.filter((mesh) => mesh.name === name)[0]
  }

  private disposeMesh(mesh: AbstractMesh) : void {
    mesh.dispose()
  }
  
  // public addModelFromImport(file: string) {
  //   console.log("before uploaded!")
  //   SceneLoader.LoadAssetContainerAsync(file).then((container) => {
  //     console.log("inside upload")
  //     container.addAllToScene();
  //     });
  //     console.log("after uploaded!")
  
  // }
//this function is I wa
  public createPlayerMesh() {
    const mesh: any = SceneLoader.ImportMesh(
        "",
       './models/',
        'Dog.glb',
        this._scene
    );
    return mesh;
}
  
}

Note: to point out again any code that is comment is because it was related to upload/import file. i thought it would start by importing mesh first in my public/models file path, then after I successfully able to import a mesh. I will work on code that is comment.

what I am trying to accomplish now? whenever I click a button it’s able to import mesh that is saved in my react project locally.

Here are the errors that I am encountering currently.
Screen Shot 2022-05-27 at 2.19.06 PM

I think it’s something to do how I am importing babylonjs. I’m not sure what I am doing wrong. If anyone Could help me? it would be greatly appreciate it. Thank you in Advance.

Maybe @sebavan or @RaananW can help

A few questions -

Are the versions of both packages (babylon core and babylon loaders) the same?
Would you be able to share a reproduction project? I will be happy to try debugging it with you

3 Likes

@RaananW it was packages version issue core and loaders were not on the same version. THANK YOU SO MUCH!!!

2 Likes