如何在AFrame中动态创建纹理

时间:2019-09-06 07:10:31

标签: aframe

我正在制作一个场景,该场景在解析json文件后根据代码生成实体。 一切正常,除了纹理加载。

为简化问题,我在此故障中重建了最低要求 https://glitch.com/~generate-scene

 <script>
        AFRAME.registerComponent("make-spheres", {
            init: function(){
                var sceneEl = document.querySelector('a-scene');
                var entityEl = document.createElement('a-entity');
                entityEl.setAttribute('id', 'sphere1');
                entityEl.setAttribute('geometry', { primitive: 'sphere', radius: 0.5});
                entityEl.setAttribute('material', { color: 'white', src: 'assets/pano_1.png', opacity: 0.5});
                entityEl.setAttribute('position',  "0 0.25 0");
                entityEl.setAttribute('animation__opacity',{ property: "components.material.material.opacity", from: 0.1, to: 1,  dur: 1500, loop: true, dir:"alternate"});
                entityEl.setAttribute('animation__pos1',{ property: 'position', to: "0 2 0", from: "0 0.85 0", dur: 1500, easing: "linear", loop: true, dir:"alternate"});
                entityEl.setAttribute('do-something-once-loaded', '');
                sceneEl.appendChild(entityEl);
            }
        });
    </script>

    <body>
        <a-scene>
        <a-entity id="setup" make-spheres></a-entity>

在这里,纹理加载并且一切正常。

但是在我的更大项目中,动态加载组件代码被隐藏在获取承诺中,纹理无法加载,并引发错误和警告。

HTTP加载失败,状态为404。媒体资源http://localhost:3000/assets/pano_1.png的加载失败。 panomaker.html 组件:纹理:警告$s不是有效的视频资产/pano_1.png

AFRAME.registerComponent("init-spheres", {
    init: function(){
        let el = this.el;
        let self = this;
        self.parent = el; // Ref to 3D entity that will be the parent of all newly created entities (spheres, buttons, etc).
        // load the json file used to populate the scene
        fetch("../data.json")
            .then(function(response){
                return response.json(); // convert data to json object
            })
            .then(function(body) { 
                // When data has been converted, start generating 3D
                //console.log('fetch data response: ', body);
                let panosArray = body.data; 

                // Create the pano objects from the json data
                self.panos = getPanoramas(panosArray); 
                   ...
                // creating sphere panos
                self.panos.forEach(function(pano){
                    // Create the pano spheres.
                    pano['sphere'] = document.createElement("a-entity");
                    pano.sphere.setAttribute('id', "panoSphere_"+pano.id);
                    pano.sphere.setAttribute('geometry', {primitive: 'sphere', radius: pano.avgDistance});                   
                    pano.sphere.setAttribute('position', pano.position.x.toString()+' '+pano.position.y.toString()+' '+pano.position.z.toString() );
                    pano.sphere.setAttribute('scale', "-1 1 1");
                    pano.sphere.setAttribute('visible', true);
                    // set the src to the pano texture. src: pano.texture, opacity: 1, shader: "flat", side:"back", npot: true, blending: "normal", 
                    let texName = "assets/"+pano.texture;
                    pano.sphere.setAttribute('material', {color: "#ffffff", src: 'assets/pano_1.png', transparent: true } ); //src: texName,
                    self.sceneEl.appendChild(pano.sphere);
                });

为什么它不能在较大的项目中加载,而在较小的项目中却可以正常工作?

问题似乎在于纹理尚未准备好加载,或者可能是某种阻止它加载的原因。我很困惑。

我注意到有两种方法可以在AFrame中加载纹理。
1)在材料中使用直接路径:src属性

material="src: texture.png"

2)将资产创建为img元素,并在材料src属性中引用其id标签。

<a-assets>
    <img id="my-texture" src="texture.png">
  </a-assets>
material="src: #my-texture"

两种方法都可以,但是首选第二种方法,因为它可以预加载纹理,可以防止错误。 我上面的代码使用方法1,该方法在简单版本中有效,而在更复杂的项目中失败。所以我想,如果我可以用代码创建一个资产资产img源,那么这可能会起作用。但是我还没有找到一种使它工作的方法。 我正在尝试

 // Create the image assets for the scene
 let assets = document.querySelector('a-assets');
 // Create the pano textures.
 let name = 'panotex_'+pano.id;

 let texture = document.createElement('img');
 texture.setAttribute('id', name);
 texture.onload = function(){
     console.log('texture loaded');
 }
 texture.onerror = function(){
      console.log('texture failed');
 }
 let texPath = "assets/"+pano.texture;
 texture.setAttribute('src', texPath);
 assets.appendChild(texture);

但这会导致纹理无法加载,并在控制台中抛出“纹理失败”。

预加载纹理,将其附加到 a-assets 并执行将在加载纹理时运行的处理函数的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

loading textures with THREE.js怎么样?

如果您有图像路径,则可以将其提供给THREE.TextureLoader对象:

// assuming this.el is the entity
var mesh = this.el.getObject3D('mesh');
var loader = new THREE.TextureLoader();
loader.load(url, 
            //onLoadCallback
            function(texture) {
              // apply the texture here
              mesh.material.map = texture
            },
            // onProgressCallback - not sure if working
            undefined,
            // onErrorCallback
            function(err) {
               console.log("error:", err)
            });

当然,您不需要立即应用纹理,您可以存储它(预加载)并在必要时使用它。

提琴here