首页 > 解决方案 > 如何在附加到 gltf 元素的自定义组件内引用多种材料

问题描述

我有一个附加了 gltf-model 组件的元素。在内部,我想使用具有组件级别范围的变量(即模式属性)来引用一些材料。我注意到(在 aframe 文档中)模式对象的类型是“字符串”或“数字”,并且我想存储对 THREE.js 材料的引用(不确定这是否有效)。我试过了,它可以工作,但范围仅限于侦听器功能,所以显然,它不起作用。如何存储对可以在组件中的任何位置访问的 THREE.objects 的引用?最终,我想存储对各种材料的许多引用,并在('model-loaded')侦听器函数之外的其他侦听器函数('loaded')中修改它们的属性。

我尝试使用模式属性来存储 THREE.material 像这样

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

但是在侦听器函数之外记录 data.bonsaiMat 什么都不返回(在侦听器函数内部工作正常)。

也试过 this.bonsaiMat = node.material; // 错误

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

我希望存储在架构中的变量,即 this.data.myMaterial 可以在组件中的任何地方使用,但范围仅限于侦听器函数,所以出了点问题。架构属性的数据类型?还有其他方法可以获得组件范围吗?我的项目相当庞大,因此将其置于故障中会很乏味,但如果需要,我可以做到。

标签: aframe

解决方案


您可以使用一个数组/对象,这将是您的组件主范围的一个属性。要获取材料,您可以遍历模型子项:

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
})


通过范围快速概览。this.stuff在以下示例中引用相同的对象:

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
   }
})


另一方面,我会尽量减少使用它。像这儿:

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 !
})

关于污染范围与垃圾收集的酷答案。


推荐阅读