在 javascript 中使用 A 帧 img 资产

Use A-frame img assets inside javascript

我多次使用图像作为纹理,一次是通过 material 组件,另一次是在自定义组件中。在后者中,我使用 THREE.TextureLoader() 导致应用程序 加载图像两次 。我敢打赌还有另一种方式。

现状

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

问题

如何在自定义组件中使用相同的图像资源而不加载它两次?

您正在使用 mesh.traverse(),它会在 mesh 的每个 child 中调用您的函数一次。如果您的网格中有两个 children,它会调用 TextureLoader.load() 两次。只需从 traverse() 中取出加载调用,您应该会看到图像只加载了一次。

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

在深入研究 ThreeJs 代码后,我发现 TextureLoader 依赖于 ImageLoader(参见 here) which, before loading a new image, it looks into THREE.Cache to see if the image has already been loaded (see here)。

在 AFrame 中以 img 加载图像不会将它们存储在 THREE.Cache 中,因此图像被加载了两次。但是,如果您将图像加载为 a-asset-item,它会加载图像。

因此 javascript 中无需更改任何内容。只需使用 a-asset-item 而不是 img

有关详细信息,请参阅 AFrame documentation