0

I have an element with a gltf-model component attached. Inside, I want to get reference to some of the materials using variables that have component level scope, ie schema properties. I notice (in the aframe docs) that the type for schema objects is 'string' or 'number', and I want to store a reference to THREE.js material (not sure if this works). I tried that, and it works, sort of, but the scope is limited to the listener function, so apparently, it's not working. How do I store references to THREE.objects that can be accessed anywhere in my component? Ultimately I want to store many references to various materials, and modify their properties in other listener functions ('loaded') outside of the ('model-loaded') listener function.

I tried to use a schema property to store the THREE.material like this

schema:{ 
  bonsaiMat:{type:'string'}...
     update:function(){ 
        let data = this.data;
          el.addEventListener('model-loaded', function(ev){
            data.bonsaiMat = node.material;

but logging data.bonsaiMat outside of the listener function returns nothing (works fine inside listener function).

Also tried this.bonsaiMat = node.material; // errors

AFRAME.registerComponent("bonsai-gltf", { 
            schema:{ 
                bonsaiMat:{type:'string'}               
            },
            update:function(){
                let el = this.el;
                let scene = el.sceneEl.object3D;
                let data = this.data;

                // Initialize materials setup on the scultpure.
                el.addEventListener('model-loaded', function(ev){
                   // console.log('bonsai loaded');
                    let mesh = el.getObject3D('mesh');

                    // Get references to Materials, to be adjusted later.
                    mesh.traverse(function(node){
                        if(node.isMesh){
                            if(node.material.name === 'pbr_Metal'){                               
                                data.bonsaiMat = node.material;
                                console.log(bonsaiMat); // <--this works
                            }                          
                        }
                    });
                 console.log(data.bonsaiMat); // <--this fails

I expected variables stored in the schema, ie this.data.myMaterial to be usable anywhere in the component, but the scope is limited to the listener function, so something is wrong. data type for schema property? Is there some other way to get component wide scope? My project is rather sprawling, so putting it inside of a glitch would be tedious, but I can do it if required.

Thomas Williams
  • 842
  • 6
  • 13
  • To put the problem another way, I have 2 event listeners, "model-loaded" for gltf and "loaded" for scene (used by dat.GUI). I want to use material references (variables) from the "model-loaded" listener function inside the "loaded" lister function. My work around is to put all the GUI functionality inside the "model-loaded" listener since that reliably loads last. Still wondering if there is a way to assign a var ref to a gltf material with component wide scope. – Thomas Williams Jul 27 '19 at 21:46

1 Answers1

1

You can use a array / object which would be a property of your components main scope. To get the materials, you can iterate through the models children:

let mesh = this.el.getObject3D('mesh')
this.materials = {}
mesh.traverse( node => {
    if (!node.isMesh())
       return;
    let material = node.material // reference to the material
    this.materials[node.uuid] = node.material // keep it in a map
})


Quick overview through scopes. this.stuff references the same object in the below example:
AFRAME.registerComponent('foo', {
   init: function() {
      this.stuff = null 
      var self = this
      // anonymous function 
      this.el.addEventListener('model-loaded', function() {
         self.stuff //= otherstuff
      }
      // lambda capture - same scope
      this.el.addEventListener('loaded', e => {
         this.stuff //= otherstuff
      })
      // custom functions need to have to scope bound (bind / apply / call)
      this.customFunction = this.customFunction.bind(this)
   },
   tick: function() {
      this.stuff //= otherstuff
   },
   customFunction: function() {
      this.stuff //= otherstuff
   }
})


On the other hand I would minimize the use of this. Like here:
var stuff // no need for this to be global if i only need it here:
this.el.addEventListener('model-loaded', function() {
    // can access stuff here !
})
this.el.addEventListener('model-loaded, e => {
    // as well as here !
})

Cool anwser on polluting scopes vs garbage collection.

Piotr Adam Milewski
  • 14,150
  • 3
  • 21
  • 42