Use A-frame img assets inside javascript

2019-08-13 09:43发布

问题:

I'm using an image as a texture several times, once via the material component, another time in a custom component. In the latter I'm using THREE.TextureLoader() which cause the application to load the image twice. I bet there's another way.

Current situation

HTML

<!-- Assets -->
<a-assets>
  <img id="my-map" src="path/to/map.jpg">
  <a-asset-item id="my-model" src=path/to/model.gltf""></a-asset-item>
</a-assets>

<!-- Entities -->
<a-box material="src: #my-map">
<a-entity gltf-model="src: #my-model" custom-component="mymap: #my-map">

JS

// custom-component extract
schema: { mymap: { type: 'map' } }
init: function() 
{
    let mesh = this.el.getObject3D('mesh')
    mesh.traverse( function( child ) 
    {
        if ( child.isMesh )
        {   
            let TextureLoader = new THREE.TextureLoader()
            let mymap = TextureLoader.load( data.mymap )

            child.material = new THREE.MeshPhongMaterial({ map: mymap })
            child.material.needsUpdate = true;
        }
    })
}

Question

How can I use the same image asset in the custom component without loading it twice?

回答1:

You're using mesh.traverse() which calls your function once per child of mesh. If you have two children in your mesh, it'll call TextureLoader.load() twice. Simply take the load call out of traverse(), and you should see the image loaded just once.

let mesh = this.el.getObject3D('mesh')
let TextureLoader = new THREE.TextureLoader()
let mymap = TextureLoader.load( data.mymap )

mesh.traverse( function( child ) 
{
    if ( child.isMesh )
    {   
        child.material = new THREE.MeshPhongMaterial({ map: mymap })
        child.material.needsUpdate = true;
    }
})


回答2:

After some research digging in ThreeJs code I've found that TextureLoader relies on ImageLoader (see here) which, before loading a new image, it looks into THREE.Cache to see if the image has already been loaded (see here).

Loading images as img in AFrame doesn't store them in THREE.Cache therefore the image was loaded twice. But if you load the image as a-asset-item it does.

So there is no need to change anything in javascript. Just use a-asset-item instead of img.

For more info see AFrame documentation