简体   繁体   English

three.js:重用纹理?

[英]three.js: reusing a texture?

In my program I have several places where I instantiate geometries, and each place has its own preferences for how their geometries are to be meshed (double sided or not? Lambert or basic material?). 在我的程序中,我有多个实例化几何的地方,每个地方都有关于如何对其几何进行网格化的偏好(是否是双面的?是否是Lambert或基本材料?)。 However, they all use the same texture. 但是,它们都使用相同的纹理。 I would like to load this common texture only once. 我只想加载一次此通用纹理。 This gives me a design problem: 这给了我一个设计问题:

When loading the texture using TextureLoader.load() , I only get to use the texture once, that is, inside the callback function that I pass to the load function. 使用TextureLoader.load()加载纹理时,我只能使用一次纹理,即在传递给load函数的回调函数内部。 This means I have to collect all my geometry instances and each of their preferences before loading my texture, such that I can make it all available (through a closure) to my callback function when the loading is initiated. 这意味着我必须在加载纹理之前收集所有几何实例以及它们的每个首选项,以便在加载开始时可以将其全部(通过闭包)提供给回调函数。

I'm thinking whether there is a canonical way to solve this problem? 我在想是否有解决此问题的规范方法? I guess other three.js users might have encountered similar situations. 我猜想其他Three.js用户可能也遇到过类似情况。 I know how I could solve this problem using promises: the load function would return a promise representing the texture. 我知道如何使用Promise解决这个问题:load函数将返回一个表示纹理的Promise。 This texture could then be passed to each of the sites that need to mesh geometries. 然后可以将此纹理传递到每个需要对几何进行网格化的位置。 This solution is convenient because I don't have to collect the big amount of geometry data merely to be able to pass it on later in one step. 该解决方案很方便,因为我不必收集大量的几何数据就可以稍后将其传递。

But is there a similar convenient, or nearly as convenient solution to this problem, that stays in the realm of callback semantics? 但是,是否存在类似的方便或几乎一样方便的解决方案,仍留在回调语义领域?

I ended up going the Promise route: wrapping the the TextureLoader.load() call in Javascripts built-in promise-returning constructor named Promise : 我最终走了Promise路线:将TextureLoader.load()调用包装在名为Promise Javascript内置内置返回承诺的构造函数中:

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 = [];

I then have a lambertMesher function that my geometry suppliers can call: 然后,我有了一个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
}

Finally, this is how I call my lambertMesher : 最后,这就是我所说的lambertMesher

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

and then, finally finally, I add my mesh to my scene like this: 然后,最后,最后,我将网格物体添加到场景中,如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM