Adding Observables to SceneLoader scene before meshes/materials are added

The project I’m working on uses FilesInput to handle loading a scene when users drag and drop files on the canvas. I’m also setting a variable (e.g. sceneMaterialsMap = new Map) to store a map that contains certain infos pertaining to the materials in the scene and use it to manage / keep track when users modify some properties of said materials (e.g. diffuseColor, etc.) through DOM inputs. For the moment, this map is built from the sceneLoaded callback, by looping through the scene’s materials:

for (let material of this.scene.materials) {
this.addToMaterialMap(material);
}

addToMaterialMap(mat) {
if (mat.getClassName() === ‘StandardMaterial’) {
mat.backFaceCulling = false;
mat.checkReadyOnlyOnce = false;
this.sceneMaterialsMap.set(mat.uniqueId, {
name: mat.name,
color: mat.diffuseColor.toHexString(),
hasTexture: mat.diffuseTexture? true : false,
showTexture: mat.diffuseTexture? true : false,
textureUid: mat.diffuseTexture? mat.diffuseTexture.uniqueId : null,
borders: mat.diffuseTexture? false : true,
bordersWidth: 5,
})
}
}

But then, later on, to ensure this map is kept up to date if the scene is modified, I’m attaching the same behavior to material observables:

this.scene.onNewMaterialAddedObservable.add((material) => this.addToMaterialMap(material));
this.scene.onMaterialRemovedObservable.add((material) => { this.sceneMaterialsMap.delete(material.uniqueId) });

I’m wondering if there was a way for me to skip the whole for…of I’m doing by adding these observables on the sceneLoader’s scene before the meshes/materials were loaded?

Also, on a sidenote, one of the visual properties I’m allowing users to play with is to toggle the display of edges (mesh.enableEdgesRendering()) on a material basis although it’s set on a mesh basis. I noticed in the docs that there’s a useMaterialMeshMap option in the scene constructor and was wondering if there was any way for me to read that map or if it was strictly for internal use and I’d have to maintain my own?

Thanks! (and amazing work with the 4.2 release!)

Concerning the second part of my question, it seems I had skipped over getBindedMeshes when reading the docs. I think it will do the trick!

For the second part, you can use material.meshMap which is a public property (hidden but still public). getBindedMeshes also works but is a little slower because it builds a new array each time you call it.

Regarding the first part, if you add the observables before you load your scene that should work.

Thanks for the clarification. I think I’ll have to review how I’m handling the loading of new files because it looks like my use of FilesInput is replacing the scene by just assigning the returned babylonScene, hence why I’m losing the observers.

this.scene = new Scene(this.engine, {useMaterialMeshMap: true});
...
this.modelImport = new FilesInput(this.engine, this.scene, 
    this.sceneLoaded.bind(this),
    this.sceneProgress.bind(this),
    null, null, () => Tools.ClearLogCache(),
    null, this.sceneError.bind(this));
...
sceneLoaded(sceneFile: File, babylonScene: Scene) {
    this.scene = babylonScene; <-- the scene becomes blank (purple bg) if I'm not assigning this
    // Doing stuff here to setup scene (center meshes, position cameras, lighting, ...)

Otherwise, for managing mesh edges on a material basis, material.meshMap works like a charm, thanks!