ImportAsyncMesh on server side without scene

Hello,
I’m using NestJS as backend framework for my project,

I’m trying to import a .glb with draco compression , which is located on the server . with SceneLoader.ImportMeshAsync

image
and I receive this error ,

Also tried reading the file as base64 .

I get the following error.
Unable to get absolute URL. Override BABYLON.Tools.GetAbsoluteUrl to a custom implementation for the current context.

I need to read the meshes bounding box. is there a way to read it without using the scene loader ? or just load them without adding them to a scene ?

public static GetAbsoluteUrl: (url: string) => string =
        typeof document === "object"
            ? (url) => {
                  const a = document.createElement("a");
                  a.href = url;
                  return a.href;
              }
            : typeof URL === "function" && typeof location === "object"
            ? (url) => new URL(url, location.origin).href
            : () => {
                  throw new Error("Unable to get absolute URL. Override BABYLON.Tools.GetAbsoluteUrl to a custom implementation for the current context.");
              };

is the current implementation of the GetAbsoluteUrl function but I guess it is not available in your server environment. You should override it to something that would work on your environment with

Tools.GetAbsoluteUrl = (url) => { return ... };

Also are you sure the rest of what you need to render is available on your backend or are you not trying to render there but simply using nullengine

I’m simply trying to use the nullable engine ,to be able to calculate a set of meshes and placing then next to each others.
but to be able to do so i need to read the mesh data . and calculate by bounding box info …

also i tried a different approach .

cc @RaananW who might know some of the nest specificities but I wonder what the error could be e.g. 404 or other ?

Hey, @M0D1,
Just checking but did you provide the XHR implementation as it’s mentioned in the docs?

well, I’ve read about it , and added it on top of my code.
buy maybe I need a NestJS Expert on this.

I believe the issue is actually the HTTP request you are doing (which should not be an HTTP request). You are reading the file from the file system, right? The file is local and is not served by any static server?

Have you tried the file: protocol, or reading the file using fs. and converting the model to a data URL? I have noticed you mentioned it before, but the code is using localhost which I am not sure is what you meant to do.

playground link
for the actual data i’m reading from the file . its working properly in the sandbox .
but when i try to make it on my backend . I receive an error

The actual .glb file is also included in the repo.

I created a github repo .
its a nestjs application , which contains the 3 cases I’m facing …

there is 3 HTTP Requests that represents my cases .

I Also implemented swagger . for easy access to requests.

Hey, I checked out your repo and I think the problem is with the model.
I had this error even for the local import;
With the model (I took seagulf.glb) from the

it works (at least local import).
I’m not sure what you’re trying to do with async loading - if you have files in your folder - just read them with eg. readFileSync.
If you want to load them from the Internet - try getting them from the Babylon mesh library maybe :slight_smile:

1 Like

the model uses draco compression .
also the models work when load them on the front end . using ImportMeshAsync .

Sorry I’m not familiar with any of that :slight_smile:
I’m just trying to help you by saying what I see and that is:

  • model.glb doesn’t work even for “local import”, the error is:
    /meshes/0/primitives/0: self is not defined
  • with the seagulf.glb it works
1 Like

you are correct ,
The becouse of the compression draco the models are not loaded properly …
and the same model without the draco compression works !

1 Like

Let me know if you need more help with this. If not - please mark best matching answer as solution :slight_smile:

i’m trying to find a solution with loading a local file with import mesh , using the ‘fs’, have you ever tried that ?

I’m not sure what you’re trying to achieve.
On the server you want to load the mesh?
You are already doing that here

You use readFileSync function of fs.
Why do you want to use ImportMesh there?

the problem is loading models compressed with draco compression.

original glb Link

when I Load it using ImportMeshAsync .


it reads the full meshes without any problems.

but when I used the following command to compress the glb.

gltf-pipeline -d --draco.compressionLevel 6 --keepUnusedElements --draco.quantizePositionBits 14 --draco.quantizeNormalBits 10 --draco.quantizeTexcoordBits 12 --draco.quantizeColorBits 10 --draco.quantizeGenericBits 12 -i 0404_600.glb -o 0404_600_draco.glb

and try loading using ImportMeshAsync …


/meshes/0/primitives/0: self is not defined

I Used the sandbox.babylon to check if the compressed file works or not , and its working .

I don’t understand how is it working in there .
do I need to connect another library ? or override some libraries to be able to read that format ?

Try using this

I Already read this , and it did not work out ,
The case is I Have the model with draco compression ( AND ITS VALID )
https://github.khronos.org/glTF-Validator/

my code

import "babylonjs";
import "babylonjs-serializers"
import "babylonjs-loaders";
global.XMLHttpRequest = require("xhr2").XMLHttpRequest;

BABYLON.Tools.GetAbsoluteUrl =
  (url): string => {
    return url;
  }

  
BABYLON.DracoCompression.Configuration = {
  decoder: {
    wasmUrl: "https://cdn.jsdelivr.net/gh/google/draco/javascript/draco_decoder.js",
    wasmBinaryUrl: "https://cdn.jsdelivr.net/gh/google/draco/javascript/draco_decoder.wasm",
    fallbackUrl: "https://cdn.jsdelivr.net/gh/google/draco/javascript/draco_wasm_wrapper.js",
  }
};

async testLocal() {
    try {
      const result = await BABYLON.SceneLoader.ImportMeshAsync(null, 'http://localhost:4000/', 'uploads/models/0294_600_draco.glb', this.scene_);
    } catch (e) {
      throw e;
    }
  }

the output .

Importing with ImportMeshAsync

importing using the folowing code

  async testLocal() {
    BABYLON.Tools.LoadFile('http://localhost:4000/uploads/models/0294_600_draco.glb',
      async (data: any) => {

        BABYLON.DracoCompression.Configuration = {
          decoder: {
            wasmUrl: "https://cdn.jsdelivr.net/gh/google/draco/javascript/draco_decoder.js",
            wasmBinaryUrl: "https://cdn.jsdelivr.net/gh/google/draco/javascript/draco_decoder.wasm",
            fallbackUrl: "https://cdn.jsdelivr.net/gh/google/draco/javascript/draco_wasm_wrapper.js",
          }
        };
        var dracoCompression = new BABYLON.DracoCompression();
        var attributes = {
          // [BABYLON.VertexBuffer.UVKind]: 0,
          // [BABYLON.VertexBuffer.NormalKind]: 1,
          // [BABYLON.VertexBuffer.TangentKind]: 2,
          [BABYLON.VertexBuffer.PositionKind]: 3
        };
        var vertexData = await dracoCompression.decodeMeshAsync(data, attributes);
        var mesh = new BABYLON.Mesh("dracoMesh", this.scene_);
        var geometry = new BABYLON.Geometry("dracoGeometry", this.scene_, vertexData, undefined, mesh);

        mesh.material = new BABYLON.PBRMaterial("material", this.scene_);
        mesh.material.sideOrientation = BABYLON.Material.CounterClockWiseSideOrientation;
      }, undefined, undefined, true);


  }

Small note - I don’t see how setting the draco URLs to different urls (and not a local copy, for example), will provide a different result.

Maybe @bghgary can provide some input here regarding the draco decoder

well, it doesn’t make any difference if i used the default configuration or if i sat different urls .
( I thought The nestjs framework had a problem loading the urls) that’s why i specified them .