Model of modelcomponent of loaded glb model is null

Hi everybody,
I’m trying to access the morphInstances of a model to set its weight values at runtime.
The entity with the glbLoadMorph script has also a model component.

The line (self.entity.model.model.morphInstances[0].setWeight(0, 1)) inside the utils function is working as expected. And the model is showing on screen.

But if I want to do the same thing later in the initialize funtion outside the util, I get the error:
TypeError: Cannot read property ‘morphInstances’ of null.

Does that mean that the model component isn’t set right in the util function? Shouldn’t the line self.entity.model.asset = asset.resource.model; set this references?

How can I access properties of the modelcomponent of a loaded glb model in script after calling the util function? To do something like this this.entity.model.model.morphInstances[0].setWeight(0, 1);

Thanks

image

var GlbLoadMorph = pc.createScript('glbLoadMorph');
GlbLoadMorph.attributes.add('glbAsset', { type: 'asset', assetType: 'binary'});

// initialize code called once per entity
GlbLoadMorph.prototype.initialize = function() {
    var self = this;
    utils.loadGlbContainerFromAsset(this.glbAsset, null, this.glbAsset.name, function (err, asset) {
        self.entity.model.asset = asset.resource.model;
        self.entity.model.model.morphInstances[0].setWeight(0, 1);

    });    
    this.entity.model.model.morphInstances[0].setWeight(0, 1);
};

with the glb-utils.js from the example project:

(function(){
    var utils = {};
    var app = pc.Application.getApplication();

    /**
     * @name utils#loadGlbContainerFromAsset
     * @function
     * @description Load a GLB container from a binary asset that is a GLB.
     * @param {pc.Asset} glbBinAsset The binary asset that is the GLB.
     * @param {Object} options Optional. Extra options to do extra processing on the GLB.
     * @param {String} assetName. Name of the asset.
     * @param {Function} callback The callback function for loading the asset. Signature is `function(string:error, asset:containerAsset)`.
     * If `error` is null, then the load is successful.
     * @returns {pc.Asset} The asset that is created for the container resource.
     */
    utils.loadGlbContainerFromAsset = function (glbBinAsset, options, assetName, callback) {
        var blob = new Blob([glbBinAsset.resource]);
        var data = URL.createObjectURL(blob);
        return this.loadGlbContainerFromUrl(data, options, assetName, function(error, asset) {
            callback(error, asset);
            URL.revokeObjectURL(data);
        });
    };

    /**
     * @name utils#loadGlbContainerFromUrl
     * @function
     * @description Load a GLB container from a URL that returns a `model/gltf-binary` as a GLB.
     * @param {String} url The URL for the GLB
     * @param {Object} options Optional. Extra options to do extra processing on the GLB.
     * @param {String} assetName. Name of the asset.
     * @param {Function} callback The callback function for loading the asset. Signature is `function(string:error, asset:containerAsset)`.
     * If `error` is null, then the load is successful.
     * @returns {pc.Asset} The asset that is created for the container resource.
     */
    utils.loadGlbContainerFromUrl = function (url, options, assetName, callback) {
        var filename = assetName + '.glb';
        var file = {
            url: url,
            filename: filename
        };

        var asset = new pc.Asset(filename, 'container', file, null, options);
        asset.once('load', function (containerAsset) {
            if (callback) {
                // As we play animations by name, if we have only one animation, keep it the same name as
                // the original container otherwise, postfix it with a number
                var animations = containerAsset.resource.animations;
                if (animations.length == 1) {
                    animations[0].name = assetName;
                } else if (animations.length > 1) {
                    for (var i = 0; i < animations.length; ++i) {
                        animations[i].name = assetName + ' ' + i.toString();
                    }
                }

                callback(null, containerAsset);
            }
        });

        app.assets.add(asset);
        app.assets.load(asset);

        return asset;
    };

    window.utils = utils;
})();

loadGlbContainerFromAsset is a asynchronous call so you have to wait till it’s finished (ie when the callback is fired) before accessing the model.

1 Like

Thank you! I haven’t thought about that.

Now I’m setting a variable to true inside the callback function. And check that before I want to set the weights. It’s working now.

utils.loadGlbContainerFromAsset(this.glbAsset, null, this.glbAsset.name, function (err, asset) {
        self.entity.model.asset = asset.resource.model;
        self.loaded = true;

    });


GlbLoadMorph.prototype.update = function(dt){
    if(this.loaded)
        this.entity.model.model.morphInstances[0].setWeight(0, 1);
    
};
1 Like