Three.js: THREE.TextureLoader() charge la même texture plusieurs fois (c'est-à-dire 20 fois ou plus)

Créé le 5 oct. 2016  ·  3Commentaires  ·  Source: mrdoob/three.js

description du problème

Le THREE.TextureLoader() se comporte de manière inattendue et erronée. La fonction load() de la classe essaie/charge les mêmes actifs plusieurs fois (c'est-à-dire 20 fois ou plus).

La figure ci-dessous illustre ce comportement à l'aide de la console du navigateur :
bdhg9

Le code utilisé pour charger et utiliser les textures est le suivant :

var Element = function (texture) {
    this.texture = texture;
};
Element.prototype.createShaderMaterial = function (uniforms, vertexShader, fragmentShader) {
    var loader = new THREE.TextureLoader();
    uniforms.texture.value = loader.load(this.texture);

    return new THREE.ShaderMaterial({
        uniforms: uniforms,
        vertexShader: vertexShader,
        fragmentShader: fragmentShader,
        wireframe: true
    });
};

À des fins de débogage, vous pouvez également trouver un aperçu en direct ici : https://alexprut.github.io/earth-defender/ et le code du jeu ici : https://github.com/alexprut/earth-defender/tree/master/ client/js

Version trois.js
  • [ ] Dév
  • [ ] r81
  • [x] r80

    Navigateur
  • [x] Tous

  • [ ] Chrome
  • [ ] Firefox
  • [ ] Internet Explorer

    Système d'exploitation
  • [x] Tous

  • [ ] Les fenêtres
  • [ ] Linux
  • [ ] Android
  • [ ] IOS
    Configuration matérielle requise (carte graphique, périphérique VR, ...)
Help (please use the forum)

Commentaire le plus utile

XHRLoader qui est appelé depuis TextureLoader via ImageLoader utilise l'objet global Cache
mais par défaut Cache.enabled est false .

Si vous définissez THREE.Cache.enabled = true; juste après le chargement de three.js
ça marcherait.

https://github.com/mrdoob/three.js/blob/2f469f327a10c7780c9bc69f876f9ed5049587f2/src/loaders/XHRLoader.js#L22

https://github.com/mrdoob/three.js/blob/f65e669af99feb518e31756d793a9688a2578fbd/src/loaders/Cache.js#L9

6834

Tous les 3 commentaires

Je pense que le chargeur fonctionne comme prévu. Il charge les textures de météores 200 fois parce que vous le lui demandez. Le chargeur peut être modifié pour mettre en cache et renvoyer automatiquement les ressources que vous lui demandez de charger plusieurs fois, mais cela peut ne pas être souhaité dans tous les cas. Le navigateur gérera le cache, donc si tous les en-têtes du fichier image sont corrects, le navigateur renverra des versions mises en cache de l'image à chaque fois.

Dans ton code :

this.maxMeteorietes = config.maxMeteorietes || 200;

Game.prototype.createMeteorites = function (numMeteorites) {
    var meteorites = new THREE.Object3D();
    for (var i = 0; i < numMeteorites; i++) {
        var meteorite = new Meteorite().create(
            this.createUniforms(),
            this.createVertexShader(),
            this.createFragmentShader()
        );

    ....

}

Meteorite.prototype.create = function (uniforms, vertexShader, fragmentShader) {
    return new THREE.Mesh(
        new THREE.SphereGeometry(5, 5, 5),
//This line is called 200 times, and as such your loader.load() function will be called 200 times.
        this.createShaderMaterial(uniforms, vertexShader, fragmentShader)
    );
};

J'envisagerais d'ajouter quelque chose comme ce qui suit :

var cache = [];
var loader = new THREE.TextureLoader();  //don't need a local version of this object

Element.prototype.createShaderMaterial = function (uniforms, vertexShader, fragmentShader) {
    if(cache[this.texture]){
        return cache[this.texture]; //cache[this.texture].clone();
    }
    uniforms.texture.value = loader.load(this.texture);

    var shader = new THREE.ShaderMaterial({
        uniforms: uniforms,
        vertexShader: vertexShader,
        fragmentShader: fragmentShader,
        wireframe: true
    });

    cache[this.texture] = shader;

    return shader;
};

Ainsi, vous gérez un cache de matériaux qui sont chargés à partir d'un tableau plutôt que régénérés à chaque fois. Cela fonctionnera bien si tous les astéroïdes ont le même matériau, ou utilisez la méthode .clone() si vous voulez que les matériaux soient différents.

Voyez si cela aide.

@calrk merci cela résout le problème.

Je pense toujours que THREE.TextureLoader() se comporte de manière inattendue, il devrait vous demander si vous souhaitez mettre en cache ou non les textures, par exemple :

var loader = THREE.TextureLoader();
loader(texture, cache = false);

Je pense que par défaut le chargeur devrait mettre en cache les textures pour des raisons de performances (si je me trompe, merci de me dire pourquoi).


Vous trouverez ci-dessous une solution simple (modèle Singleton / Modèle de module) module de cache :

var TextureLoader = (function () {
    var _instance = null;

    var Loader = function () {
        var _loader = new THREE.TextureLoader();
        var _cache = [];

        function _cachePush(elem, val) {
            _cache.push({
                element: elem,
                value: val
            });
        }

        function _cacheSearch(elem) {
            for (var i = 0; i < _cache.length; i++) {
                if (_cache[i].element === elem) {
                    return _cache[i].value;
                }
            }

            return false;
        }

        function load(texture) {
            var match = _cacheSearch(texture);

            if (match) {
                return match;
            }

            var val = _loader.load(texture);
            _cachePush(texture, val);

            return val;
        }

        return {
            load: load
        }
    };

    function getInstance() {
        return (_instance) ? _instance : _instance = Loader();
    }

    return {
        getInstance: getInstance
    }
})();

Pour utiliser et mettre en cache la texture, vous devez appeler :

TextureLoader.getInstance().load(texture);

XHRLoader qui est appelé depuis TextureLoader via ImageLoader utilise l'objet global Cache
mais par défaut Cache.enabled est false .

Si vous définissez THREE.Cache.enabled = true; juste après le chargement de three.js
ça marcherait.

https://github.com/mrdoob/three.js/blob/2f469f327a10c7780c9bc69f876f9ed5049587f2/src/loaders/XHRLoader.js#L22

https://github.com/mrdoob/three.js/blob/f65e669af99feb518e31756d793a9688a2578fbd/src/loaders/Cache.js#L9

6834

Cette page vous a été utile?
0 / 5 - 0 notes