ES6 Version: GLTF2 and GLTFLoader

YO @bghgary are there any changes in the way you register gltf extensions with the ES6 version of babylon js.

I compiled my toolkit with the GLTF Parser for Unity Metadata. I been using that for years now, you know that already. But what is weird with the ES6 version is that i register these guys the same way:

GLTF2.GLTFLoader.RegisterExtension(TOOLKIT.SceneManager.CVTOOLS_NAME, (loader) => new TOOLKIT.CVTOOLS_unity_metadata(loader));
GLTF2.GLTFLoader.RegisterExtension(TOOLKIT.SceneManager.CVTOOLS_MESH, (loader) => new TOOLKIT.CVTOOLS_babylon_mesh(loader));
GLTF2.GLTFLoader.RegisterExtension(TOOLKIT.SceneManager.CVTOOLS_HAND, (loader) => new TOOLKIT.CVTOOLS_left_handed(loader));

And I see them in the console, but the app keeps saying they are not registered

cc @ryantrem

You should call register on an imported GLTFLoader and not the global one I guess…

It is possible you might have two contexts, depending on how you import the GLTFLoader.

Just a question (that might be related but might not :slight_smile: ) - why is the GLTF2 namespace needed? why don’t you just import the GLTFLoader as is? How are you importing the loaders package? are the versions the same (core and loaders)?

OK… GLTF2 and GLTFLoader in my ES6 builds. First of all i am trying to mirror functionality from my main UMD build. For my GLTF parser i was using alot of classes in my PARSER functions:

BABYLON.GLTF2.GLTFLoader
BABYLON.GLTF2.IGLTFLoaderExtension
BABYLON.GLTF2.Loader.IScene
BABYLON.GLTF2.Loader.INode
BABYLON.GLTF2.IMaterial
BABYLON.GLTF2.Loader.IAnimation
BABYLON.GLTF2.ArrayItem
BABYLON.GLTF2.INode
BABYLON.GLTF2.IMesh
BABYLON.GLTF2.IMeshPrimitive

Once I moved over to the ES6 @babylonjs versions, and to keep my same codebase for my gltf parser, I removed the BABYLON from all the references above… Leaving GLTF2.GLTFLoader and etc…

I use a centralized import to gather all the classes above that come from different sources into once export called GLTF2 to mimic what the UMD version signatures look. So I can use the same exact GLTF PARSING code for both UMD and ESM Builds. So its is actually using imports and not globals:

this is a file i call babylon-gltf where i centralize all my GLTFLoader type imports to a fake namespace called GLTF2

// Import from the ES6 version of BabylonJS
import { GLTFLoader } from '@babylonjs/loaders/glTF/2.0/glTFLoader';
import { IGLTFLoaderExtension } from '@babylonjs/loaders/glTF/2.0/glTFLoaderExtension';
import { IScene, INode, IMaterial, IAnimation, IMesh, IMeshPrimitive } from '@babylonjs/loaders/glTF/2.0/glTFLoaderInterfaces';
import { ArrayItem } from '@babylonjs/loaders/glTF/2.0/glTFLoader';
import { GLTFFileLoader } from '@babylonjs/loaders/glTF';
export { GLTFLoader, GLTFFileLoader, IGLTFLoaderExtension, IScene, INode, IMaterial, IAnimation, IMesh, IMeshPrimitive, ArrayItem }

Then i make imports in code to reference them like so:

import * as GLTF2 from './babylon-gltf';

In the UMD it would still be the global BABYLON.GLTF2.GLTFLoader.RegisterExtension and on ESM it would be GLTF2.GLTFLoader.RegisterExtension.

So in ESM, GLTF2.GLTFLoader is really being directly imported from @babylonjs/loaders/glTF/2.0/glTFLoader

So that makes me ask if the endpoints for my GLTF2 imports are correct. These paths ChatGPT help me find the equivalent UMD to ESM for each of BABYLON.GLTF2 classes
listed above

Should the import for GLTFLoader be:

import { GLTFLoader } from '@babylonjs/loaders/glTF/2.0/glTFLoader';

and 

import { IGLTFLoaderExtension } from '@babylonjs/loaders/glTF/2.0/glTFLoaderExtension';

and 

import { IScene, INode, IMaterial, IAnimation, IMesh, IMeshPrimitive } from '@babylonjs/loaders/glTF/2.0/glTFLoaderInterfaces';

Cause i was getting error if i tried something:

import { GLTFLoader } from '@babylonjs/loaders';

and

import { IGLTFLoaderExtension } from '@babylonjs/loaders';

and 

import { IScene, INode, IMaterial, IAnimation, IMesh, IMeshPrimitive } from '@babylonjs/loaders';

Crap…I tried these imports as well.

import { GLTFFileLoader } from '@babylonjs/loaders/glTF';
import { GLTFLoader, ArrayItem, IGLTFLoaderExtension, IScene, INode, IMaterial, IAnimation, IMesh, IMeshPrimitive } from '@babylonjs/loaders/glTF/2.0';
export { GLTFFileLoader, GLTFLoader, ArrayItem, IGLTFLoaderExtension, IScene, INode, IMaterial, IAnimation, IMesh, IMeshPrimitive };

But still keep getting my extension is not registered but I can see it GLTFLoader._RegisteredExtensions… Bummer :frowning:

import { GLTFLoader } from '@babylonjs/loaders/glTF/2.0/glTFLoader'; should work correctly.

When you say “But still keep getting my extension is not registered but I can see it GLTFLoader._RegisteredExtensions” (and you showed a debugger screenshot earlier with something similar), at what point during code execution are you seeing that? Can you put a breakpoint GLTFLoader._checkExtensions and check there? If your extension isn’t in the list at that point, then I would check to see if the GLTFLoader is actuall the same class or through some module wonkiness you ended up with two. I expect you could check by just adding some random property to GLTFLoader at your first breakpoint and checking it is there at your second breakpoint.

I just created a standalone Vite project from scratch and pulled in the latest BJS ES6 packages and tested this flow with a glTF and a required extension and I could not repro any issue locally. :confused:

Yo @ryantrem

Can I see that project ?

What do all your imports look like ?

Do you register a custom extension with GLTFLoader.RegisterExtension ?

And When do your call RegisterExtension ?

Sure as shit, your right, they are not there, WTF

But they do show up (eventually) on GLTFLoader._RegisteredExtensions … HMMM

Im gonna try remove where i Register the extension and put it on demand for a sec and try and register right before i load the gltf file… maybe its a timing thing ?

This is pretty much all I did to test:

import { GLTFLoader } from '@babylonjs/loaders/glTF/2.0';
import { SceneLoader } from '@babylonjs/core/Loading/sceneLoader';

GLTFLoader.RegisterExtension('ryan', (loader) => {
  return {
    name: 'ryan',
    loadSceneAsync: (context, scene) => {
      console.log("LOAD SCENE");
    }
  }
});

SceneLoader.LoadAssetContainerAsync("https://raw.githubusercontent.com/BabylonJS/Assets/master/meshes/LevelOfDetail.glb");

There should not be any timing issue possible as far as I can tell. It seems more likely there is a duplicated module issue. I would try the thing I mentioned earlier, just plopping a random property on the GLTFLoader in both places and see if they are the same.

I just tried to run test ryan extension and i get this error

There is something rotten in denmark with my host project i guess

I believe this PG may help - https://playground.babylonjs.com/#XL1M1C#1
Ryan’s example has the same error in PG - Babylon.js Playground

Crap nuts again… This time i totally inlined everything in one index.ts that has the whole … STILL My extensions dont get loaded.

Attached is my whole lib for es6
index.ts.zip (159.4 KB)

Preview

/** ES6 Module Imports */
import * as BABYLON from '@babylonjs/core';
import '@babylonjs/materials';
import '@babylonjs/loaders/glTF';
import HavokPhysics from "@babylonjs/havok";
import { PhysicsViewer } from '@babylonjs/core/Debug/physicsViewer';
import { GLTFFileLoader } from '@babylonjs/loaders/glTF';
import { GLTFLoader, ArrayItem, IGLTFLoaderExtension, IScene, INode, IMaterial, IAnimation, IMesh, IMeshPrimitive } from '@babylonjs/loaders/glTF/2.0';
import GLTF2INTERFACE from 'babylonjs-gltf2interface';

// ******************************* //
// * Babylon Loader Plugins      * //
// ******************************* //

public static RegisterLoaderPlugins(): void {
    GLTFLoader.RegisterExtension(TOOLKIT.SceneManager.CVTOOLS_NAME, (loader) => new TOOLKIT.CVTOOLS_unity_metadata(loader));
    GLTFLoader.RegisterExtension(TOOLKIT.SceneManager.CVTOOLS_MESH, (loader) => new TOOLKIT.CVTOOLS_babylon_mesh(loader));
    GLTFLoader.RegisterExtension(TOOLKIT.SceneManager.CVTOOLS_HAND, (loader) => new TOOLKIT.CVTOOLS_left_handed(loader));
}

At Bottom Of Module

/** Babylon Toolkit Runtime Module */
if (typeof window !== 'undefined') {
    (window as any).TOOLKIT = TOOLKIT;
}
TOOLKIT.SceneManager.RegisterLoaderPlugins();
export default TOOLKIT;

Sorry I just setup a minimal test in JavaScript, enough for it to work at runtime. You are seeing TypeScript type errors (not runtime errors).

@ryantrem is your latest PR on types addressing those ? just to know if I should deploy a patch

No my latest PR is unrelated (or at least I don’t expect it to impact this issue).

@MackeyK24

  1. I would try the thing I mentioned earlier, just plopping a random property on the GLTFLoader in both places and see if they are the same. Can you please try this so we know whether you have more than one copy of the GLTFLoader class at runtime?
  2. Can you share your final bundled JS that the browser is actually loading?

I think a had a couple issues with packaging my toolkit. But after days and days working with ChatGPT and trying every configuration in the world. I finally got my Toolkit packaged and can now use my toolkit using npm:

Classic Edition

Next Edition

2 Likes

Congrats !!!

Yo @RaananW … Thanks again for the guidance.

Here here the fruits of all that labor:

Babylon Toolkit Running As A Native Node Modules

2 Likes