Getting custom properties of a 3D model

I have a problem getting custom .glb properties after exporting from Blender
I just get null

In three.js I can just get the userData and see the model’s custom properties

How to implement this in Babylon?
Additional import (Module not found: Can’t resolve ‘babylonjs-loaders/glTF/2.0/Extensions/ExtrasAsMetadata’) throws an error

import * as BABYLON from 'babylonjs';
import 'babylonjs-loaders';


interface LoadedResource {
    name: string;
    resource: any;
}

export enum TypeResource {
    OBJECT = 0,
    VEHICLE = 1,
    COLLISION = 2
}

export class ResourceLoader {
    private scene: BABYLON.Scene;
    private assetsManager: BABYLON.AssetsManager;

    private loadedMeshes: LoadedResource[] = [];
    private loadedSounds: LoadedResource[] = [];

    constructor(scene: BABYLON.Scene) {
        this.scene = scene;
        this.assetsManager = new BABYLON.AssetsManager(scene);
    }

    public loadMesh(name: string, uniqueName: string, typeResource: TypeResource, carNumber?: number, onSuccess?: (mesh: BABYLON.AbstractMesh) => void, onError?: () => void) {

        let task = null;

        switch (typeResource) {
            case TypeResource.OBJECT:
                task = this.assetsManager.addMeshTask(name, "", "./models/", name + ".glb");
                break;
            case TypeResource.VEHICLE:
                task = this.assetsManager.addMeshTask(name, "", `./models/vehicles/car_${carNumber}/`, name + ".glb");
                break;
            case TypeResource.COLLISION:
                task = this.assetsManager.addMeshTask(name + "_col", "", `./models/collision/`, name + ".glb");
                break;
        }

        if (uniqueName == "" && typeResource == TypeResource.VEHICLE) {
            uniqueName = `car_${carNumber}_${name}`
        }
        else {
            uniqueName = name;
        }

        task.onSuccess = (task) => {
            // Сохраняем загруженный меш
            this.loadedMeshes.push({
                name: uniqueName,
                resource: task.loadedMeshes[0] as BABYLON.AbstractMesh
            });
            console.log(task.loadedMeshes[0].metadata)
            
            this.scene.removeMesh(task.loadedMeshes[0], true);
        }

        task.onError = (task, message, exception) => {
            console.error(task, message, exception);
        }
    }

    public getMesh(uniqueName: string): BABYLON.AbstractMesh {

        const mesh = this.loadedMeshes.find(m => m.name === uniqueName);

        if (mesh) {
            // Возвращаем копию меша
            this.scene.removeMesh(mesh.resource, true);
            return mesh.resource;
        } else {
            throw new Error("Mesh not found");
        }
    }

    public loadTexture(name: string, onSuccess: (texture: BABYLON.Texture) => void, onError: () => void) {

        const url = "/models/" + name + ".png";

        const task = this.assetsManager.addTextureTask(name, url);

        task.onSuccess = (task) => {
            onSuccess(task.texture);
        }

        task.onError = (task, message, exception) => {
            console.error(task, message, exception);
        }

    }

    public loadCubeTexture(name: string, onSuccess: (texture: BABYLON.CubeTexture) => void, onError: () => void) {

        const url = "/models/" + name;

        const task = this.assetsManager.addCubeTextureTask(name, url);
        task.onSuccess = (task) => {
            onSuccess(task.texture);
        }

        task.onError = (task, message, exception) => {
            console.error(task, message, exception);
        }

    }

    public loadSound(name: string, onSuccess: (sound: BABYLON.Sound) => void, onError: () => void) {

        const url = "/models/" + name + ".wav";

        const task = this.assetsManager.addBinaryFileTask(name, url);

        task.onSuccess = (task) => {
            const sound = new BABYLON.Sound(name, task.data, this.scene);

            this.loadedSounds.push({
                name: name,
                resource: task.data
            });

            onSuccess(sound);
        }

        task.onError = (task, message, exception) => {
            console.error(task, message, exception);
        }

    }

    public getSound(uniqueName: string): BABYLON.Sound {

        const sound = this.loadedSounds.find(s => s.name === uniqueName);

        if (sound) {
            return sound.resource;
        } else {
            throw new Error("Sound not found");
        }

    }

    public load() {
        return new Promise<void>(resolve => {
            this.assetsManager.onFinish = () => {
                resolve();
            };

            this.assetsManager.load();
        })
    }

}

console.log(task.loadedMeshes[0].metadata) - null

My additional question is why after calling the load method the mesh is automatically added to the scene? How to disable this without removing the mesh from the scene each time it is received

Got the first question

Try using assetContainers and instantiateModelsToScene.
Here’s a PG:

1 Like

How are you importing the library? CDN, npm…? Looks like there’s something happening with the modules @RaananW

do I understand correctly that there is now no longer an issue with the module resolution?