three.js:重用纹理?

时间:2015-12-27 15:17:06

标签: javascript three.js

在我的程序中,我有几个地方可以实例化几何图形,并且每个地方都有自己的几何形状的网格偏好(双面或不双面?兰伯特或基本材质?)。但是,它们都使用相同的纹理。我想只加载一次这种常见纹理。这给我一个设计问题:

使用TextureLoader.load()加载纹理时,我只能使用纹理一次,也就是说,在我传递给load函数的回调函数中。这意味着我必须在加载纹理之前收集所有几何实例和它们的每个首选项,以便在启动加载时我可以将它(通过闭包)全部用于我的回调函数。

我在想是否有一种规范的方法可以解决这个问题?我猜其他three.js用户可能遇到过类似的情况。我知道如何使用promises解决这个问题:load函数会返回一个表示纹理的promise。然后可以将此纹理传递到需要网格几何的每个网站。这个解决方案很方便,因为我不需要收集大量的几何数据,只是为了能够在以后的一步中传递它。

但对于这个问题,是否有一个类似的方便或几乎方便的解决方案,它仍然存在于回调语义领域?

1 个答案:

答案 0 :(得分:0)

我最终进入了Promise路由:在Javascripts内置的promise-returns构造函数TextureLoader.load()中包装Promise调用:

var loadTexture_promise = ( texture_path, texture_loader ) => {
    var texture_promise;

    if (       loadTexture_promise.texturePromises_cache[texture_path] !== undefined ) {
        return loadTexture_promise.texturePromises_cache[texture_path]
    }

    texture_promise = new Promise(
        function( resolve, reject )
        {
            texture_loader.load(
                texture_path,
                function (texture) {
                    // Success callback of TextureLoader
                    // We're done, so tell the promise it is complete
                    resolve(texture);
                },
                function (XmlHttpRequest_instance) {
                    // Progress callback of TextureLoader
                },
                function (unknown_parameter) {
                    // Failure callback of TextureLoader
                    // Reject the promise with the failure
                    reject(new Error('Could not load texture ' + texture_path));
                }
            );
        }
    );

    // add texture_promise to cache:
    loadTexture_promise.texturePromises_cache[texture_path] = texture_promise;

    return texture_promise;
};
// establish cache object on the loadTexture_promise function:
loadTexture_promise.texturePromises_cache = [];

然后我有一个lambertMesher函数,我的几何供应商可以调用它:

function lambertMesher ( aGeometry, aTexture_promise, doubleSided, debug ) {
    var aMesh_promise = aTexture_promise.then(
        ( resolved_texture ) =>
        {
            var material, mesh;

            if ( debug ) {
                console.log("resolved_texture: ", resolved_texture);
                console.log("aGeometry: ", aGeometry);
            }

            resolved_texture.minFilter = THREE.NearestFilter;

            if (doubleSided) {
                material = new THREE.MeshLambertMaterial( { map: resolved_texture, side: THREE.DoubleSide } );
            } else {
                material = new THREE.MeshLambertMaterial( { map: resolved_texture, emissive: 0xffffff } );
            }

            mesh = new THREE.Mesh(aGeometry, material);
            if ( debug ) {
                console.log("mesh: ", mesh);
            }
            return mesh

        },
        ( reason_of_textureLoading_failure ) =>
        {
            console.log( "meshing failed. Also: " + reason_of_textureLoading_failure )
        }
    );

    return aMesh_promise
}

最后,这就是我调用lambertMesher的方式:

var myPlateGeom = new THREE.PlateGeometry( myPlatePolygonSet, true );
var myPlateMesh_promise = utils_meshers.lambertMesher( myPlateGeom, myRobinieTexture_promise, true, false );

然后,最后,我将我的网格添加到我的场景中:

myPlateMesh_promise.then(
    (myPlateMesh) => { myScene.add( myPlateMesh ) },
    (reason)     =>   console.log( "failed to add myPlateMesh. Also: " + reason )
);