How to load local obj files in react?

Dear forum friends, I am working on an editor, and would like to import local obj files to the scene. I built the editor with react, and everything is updated in the react.useeffect(), from my ui, I had a import button, that basically will let you import something, and I tried to load some obj files.

Here is the main code:

import React from "react";

import * as BABYLON from 'babylonjs';
import 'babylonjs-loaders';
import {
  ArcRotateCamera,
  Color3,
  Vector3,
  HemisphericLight,
  MeshBuilder,
  Mesh,
  UtilityLayerRenderer,
  PositionGizmo,
  RotationGizmo,
  HighlightLayer,

} from "@babylonjs/core";
import { GridMaterial } from "@babylonjs/materials";
import SceneComponent from "./SceneComponent";
import "./ViewPortComponent.css";

let translategizmo = null;
let rotategizmo = null;
let utilLayer = null;
let highlight = null;

const ViewPortComponent = (props) => {
  const { settingData, setSettings, addData, setAdd, fileControl, setFileControl } = props;
  const sceneRef = React.useRef(null);

  React.useEffect(() => {
    const scene = sceneRef.current;

    if (scene) {
      if (fileControl.fileadd){
       // Question:
       // I am testing the loader, by storing a obj file under src/assets/example folder, so is this the correct way to import it? how can I load a local obj anywhere in my disk? like the way we put it in sandbox.babylon.com?

       // the obj is not loaded with errors:
>  Unhandled expression at line : <!DOCTYPE html>
> babylonjs.loaders.min.js:16 Unhandled expression at line : <html lang="en">
> babylonjs.loaders.min.js:16 Unhandled expression at line : <head>
> babylonjs.loaders.min.js:16 Unhandled expression at line : <meta charset="utf-8" />
> babylonjs.loaders.min.js:16 Unhandled expression at line : <link rel="icon" href="/amrgl/favicon.ico" />
> babylonjs.loaders.min.js:16 Unhandled expression at line : <meta name="viewport" content="width=device-width, initial-scale=1" />
> babylonjs.loaders.min.js:16 Unhandled expression at line : <meta name="theme-color" content="#000000" />
> babylonjs.loaders.min.js:16 Unhandled expression at line : <meta
> babylonjs.loaders.min.js:16 Unhandled expression at line : name="description"
> babylonjs.loaders.min.js:16 Unhandled expression at line : content="Web site created using create-react-app"
> babylonjs.loaders.min.js:16 Unhandled expression at line : />
> babylonjs.loaders.min.js:16 Unhandled expression at line : <link rel="apple-touch-icon" href="/amrgl/logo192.png" />
> babylonjs.loaders.min.js:16 Unhandled expression at line : <!--
> babylonjs.loaders.min.js:16 Unhandled expression at line : manifest.json provides metadata used when your web app is installed on a
> babylonjs.loaders.min.js:16 Unhandled expression at line : user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
> babylonjs.loaders.min.js:16 Unhandled expression at line : -->
> babylonjs.loaders.min.js:16 Unhandled expression at line : <link rel="manifest" href="/amrgl/manifest.json" />
> babylonjs.loaders.min.js:16 Unhandled expression at line : <!--
> babylonjs.loaders.min.js:16 Unhandled expression at line : Notice the use of /amrgl in the tags above.
> babylonjs.loaders.min.js:16 Unhandled expression at line : It will be replaced with the URL of the `public` folder during the build.
> babylonjs.loaders.min.js:16 Unhandled expression at line : Only files inside the `public` folder can be referenced from the HTML.
> babylonjs.loaders.min.js:16 Unhandled expression at line : Unlike "/favicon.ico" or "favicon.ico", "/amrgl/favicon.ico" will
> babylonjs.loaders.min.js:16 Unhandled expression at line : work correctly both with client-side routing and a non-root public URL.
> babylonjs.loaders.min.js:16 Unhandled expression at line : Learn how to configure a non-root public URL by running `npm run build`.
> babylonjs.loaders.min.js:16 Unhandled expression at line : -->
> babylonjs.loaders.min.js:16 Unhandled expression at line : <title>React App</title>
> babylonjs.loaders.min.js:16 Unhandled expression at line : </head>
> babylonjs.loaders.min.js:16 Unhandled expression at line : <body>
> babylonjs.loaders.min.js:16 Unhandled expression at line : <noscript>You need to enable JavaScript to run this app.</noscript>
> babylonjs.loaders.min.js:16 Unhandled expression at line : <div id="root"></div>
> babylonjs.loaders.min.js:16 Unhandled expression at line : <!--
> babylonjs.loaders.min.js:16 Unhandled expression at line : This HTML file is a template.
> babylonjs.loaders.min.js:16 Unhandled expression at line : If you open it directly in the browser, you will see an empty page.
> babylonjs.loaders.min.js:16 Unhandled expression at line : You can add webfonts, meta tags, or analytics to this file.
> babylonjs.loaders.min.js:16 Unhandled expression at line : The build step will place the bundled scripts into the <body> tag.
> babylonjs.loaders.min.js:16 Unhandled expression at line : To begin the development, run `npm start` or `yarn start`.
> babylonjs.loaders.min.js:16 Unhandled expression at line : To create a production bundle, use `npm run build` or `yarn build`.
> babylonjs.loaders.min.js:16 Unhandled expression at line : -->
> babylonjs.loaders.min.js:16 Unhandled expression at line : <script src="/amrgl/static/js/bundle.js"></script><script src="/amrgl/static/js/0.chunk.js"></script><script src="/amrgl/static/js/main.chunk.js"></script></body>
> babylonjs.loaders.min.js:16 Unhandled expression at line : </html>
> babylon.js:16 BJS - [00:25:16]: Setting vertex data kind 'position' with an empty array
> e._WarnEnabled @ babylon.js:16
> e.set @ babylon.js:16
> t.setVerticesData @ babylon.js:16
> e._applyTo @ babylon.js:16
> e.applyToMesh @ babylon.js:16
> e._parseSolid @ babylonjs.loaders.min.js:16
> e.importMeshAsync @ babylonjs.loaders.min.js:16
> e.loadAsync @ babylonjs.loaders.min.js:16
> (anonymous) @ babylon.js:16
> f @ babylon.js:16
> e @ babylon.js:16
> onReadyStateChange @ fileTools.ts:397
> XMLHttpRequest.send (async)
> WebRequest.send @ webRequest.ts:135
> retryLoop @ fileTools.ts:422
> requestFile @ fileTools.ts:425
> FileTools.RequestFile @ fileTools.ts:461
> Scene._requestFile @ scene.ts:4784
> g @ babylon.js:16
> e @ babylon.js:16
> Se.a.OfflineProviderFactory @ babylon.js:16
> e._LoadData @ babylon.js:16
> e.Append @ babylon.js:16
> (anonymous) @ ViewPortComponent.js:72
> invokePassiveEffectCreate @ react-dom.development.js:23487
> callCallback @ react-dom.development.js:3945
> invokeGuardedCallbackDev @ react-dom.development.js:3994
> invokeGuardedCallback @ react-dom.development.js:4056
> flushPassiveEffectsImpl @ react-dom.development.js:23574
> unstable_runWithPriority @ scheduler.development.js:646
> runWithPriority$1 @ react-dom.development.js:11276
> flushPassiveEffects @ react-dom.development.js:23447
> (anonymous) @ react-dom.development.js:23324
> workLoop @ scheduler.development.js:590
> flushWork @ scheduler.development.js:545
> performWorkUntilDeadline @ scheduler.development.js:157
 

        BABYLON.SceneLoader.Append("myprojectname/assets/example/", "metal_shelf.obj", scene, function (scene) 
      {
         // do something with the scene
      });
      setFileControl({ ...fileControl, fileadd: false }); // change state and re-render
      }

    }
  }, [settingData, addData, fileControl]);

  const onSceneReady = (scene) => {
    sceneRef.current = scene;
    let camera = new ArcRotateCamera(
      "mainCamera",
      0,
      0,
      10,
      new Vector3(0, 0, 0),
      scene
    );
    camera.setPosition(new Vector3(0, 500, -600));
    const canvas = scene.getEngine().getRenderingCanvas();
    camera.attachControl(canvas, true);
    let light = new HemisphericLight("light", new Vector3(0, 500, 0), scene);
    light.intensity = 0.7;
    // initial ground
    let ground = MeshBuilder.CreateGround(
      "plane",
      { width: settingData.planesize, height: settingData.planesize },
      scene
    );
    let groundMaterial = new GridMaterial("groundMaterial", scene);
    //... 
  };
  /**
   * Will run on every frame render.  We are spinning the box on y-axis.
   */
  const onRender = (scene) => {

  };

  return (
    <SceneComponent
      antialias
      onSceneReady={onSceneReady}
      onRender={onRender}
      id="viewport"
    ></SceneComponent>
  );
};

export default ViewPortComponent;

can someone tell me how do I use the loader? I put the question and error in the comments with the loader.

Many many thanks!

Hi,

you are mixing es6 modules and UMD modules, which won’t work as you’d expect. The first 2 lines are using UMD, the lines after are using the ES6 packages. Remove the first 2 lines, and import @babylonjs/loaders instead of babylonjs-loaders

Hi @RaananW , yes I noticed, and I changed to ES6, the errors are gone. thanks for the speedy response.

I am still interested in how to load any local file on disk tho, if you could give me some directions, I really appreciate it!

We do support the file:// protocol which should work, but i would recommend hosting your file on a local server (maybe together with the site itself?)

1 Like