brianzinn / react-babylonjs

React for Babylon 3D engine
https://brianzinn.github.io/react-babylonjs/
809 stars 102 forks source link

importMesh of undefined from undefined version: undefined, exporter version: undefinedimportMesh has failed JSON parse #262

Closed DenysAshikhin closed 1 month ago

DenysAshikhin commented 1 year ago

Hi all,

I am trying to import a .glb file on the front-end, which is being served from a server.

On the server the file is served as:

app.get('/assets/*', (req, res) => {
  console.log(req.query);
  if (!req.query.asset) {
    return res.send("no asset provided!");
  }
  let file = path.join(__dirname, 'assets_stream', req.query.asset);

  try {
    if (fs.existsSync(file)) {
      console.log(`returning: ${file}`);
      res.set('Content-Disposition', `attachment; filename="${req.query.asset}"`);

      return res.sendFile(file);
    }
    else {
      console.log(`could not find: ${file}`);
      return res.send(`file does not exist: ${req.query.asset}`);
    }
  } catch (err) {
    console.error(err);
    return res.send(`file does not exist`);
  }
});

On the front-end the model is being loaded as:

  <Model
        rootUrl={"http://localhost/assets/t?asset="}
        sceneFilename={"asset_tracking_bay_2O.glb"}
   >
      </Model>

Which leads to the error:

2sceneLoader.ts:732 Uncaught RuntimeError: Unable to load from http://localhost/assets/t?asset=asset_tracking_bay_2O.glb: importMesh of undefined from undefined version: undefined, exporter version: undefinedimportMesh has failed JSON parse
    at errorHandler (sceneLoader.ts:732:1)
    at Object.importMesh (babylonFileLoader.ts:895:1)
    at sceneLoader.ts:779:1
    at dataCallback (sceneLoader.ts:552:1)
    at fileTools.ts:385:1
    at fileTools.ts:546:1
    at transaction.oncomplete (database.ts:554:1)

I know the file itself is fine since I can load it no problem if I serve it from the public folder (rootUrl={./}). And if I try to the link in the browser, it downloads the file properly.

I'm guessing my problem is the way I'm sending the file, but I couldn't find anything specifying how to prepare a file for sending?

As always, thanks for any help!

brianzinn commented 1 year ago

Did you try serving using static?

DenysAshikhin commented 1 year ago

Thanks, that fixed it. Now serving as: app.use('/assetv2', express.static(path.join(__dirname, 'assets_stream'))); However, I have an issue for my models where I use multiples.

This works:

   <Model
        rootUrl={"http://localhost/assetv2/"}
        sceneFilename={`core_block.glb`}
      ></Model>

but I only get 1 model instead of several compared to when I do:

   <Model
        rootUrl={"http://localhost/assetv2/"}
        sceneFilename={`core_block.glb?id=${id}`}
      ></Model>

I get this error with the ID now:

Uncaught RuntimeError: Unable to load from http://localhost/assetv2/core_block.glb?id=core-34: RuntimeError: Unexpected magic: 1868833084
    at errorHandler (sceneLoader.ts:732:1)
    at errorCallback (sceneLoader.ts:577:1)
    at glTFFileLoader.ts:632:1

which wasn't happening before when loading from local (public) folder

brianzinn commented 1 year ago

I can check when I get to a computer. You may need a wildcard on the “use”. The Model component uses the url to build a cache for react Suspense. That part makes loading the “same” file multiple times a bit more interesting. If it’s the same file then I have a recipe.

DenysAshikhin commented 1 year ago

Sounds good, it is the same file but used for different objects (each having their own position and internal information). So the Id is used to separate them... I'll look forward to your fix!

brianzinn commented 1 year ago

I'll copy what I put in #144 here:

" Yes, that is a good question. It has popped up before and it actually deserves a "recipe" page on it's own. Here is an example from another issue that is similar and explains the mechanism and why it is not working for you. https://github.com/brianzinn/react-babylonjs/issues/129

For a way to declare instances of existing meshes there are examples linked from here: https://github.com/brianzinn/react-babylonjs/issues/104

If that doesn't provide a solution then we can look into a way to influence the caching using by Suspense, which is the root cause of the issue. I would actually be happy to work with you on a better solution and storybook example, because in the game that I built what I did was loaded the mesh and then created instances from that first mesh - instanced meshes have better performance. "

Does that answer your question? Depending on your use case there's an instanced mesh storybook as well: https://brianzinn.github.io/react-babylonjs/?path=/story/babylon-basic--instances

DenysAshikhin commented 1 year ago

What the user in #144 is requesting is exactly what I am trying to achieve as well. However, I need each .glb file (mesh?) to be it's own object (exactly how is) so I can attach different functionality depending on my own logic. And different might have attached objects to them (hit boxes).

It seems like the above examples are more for just displaying a copy of an existing mesh (.glb?) without actually creating an entire object for me to work with.

Please correct me if I'm wrong, but I need the whole kinda deal

brianzinn commented 1 year ago

do you have time to make a code sandbox - i don't know why hitboxes can't be attached to copies, for example.

DenysAshikhin commented 1 year ago

https://codesandbox.io/s/broken-rain-2d5l62?file=/src/worker.jsx

The above sandbox has the model I'm using, it's a bit simpler in that I don't have any logic active for rotating the model + changing animation based on if it's walking or not, but all of that would be handled in the before render hook.

My question here is, how should we use the instancing to have individual copies of the mesh animation that I can manipulate individualy+seperately from each other.

You can also see, only the last one shows up, since he is the last one to call the mesh?

brianzinn commented 1 month ago

ok - i imagine you solved this with using instances. there are some recipes for that. the underlying issue is how babylon.js loads models to the scene. there is an intermediate format proposal that will make this easier to work with and allow even pre-load: https://github.com/BabylonJS/Babylon.js/issues/14567