THREE.TextureLoader () se comporta de forma inesperada y errónea. La función load () de la clase intenta / carga los mismos activos varias veces (es decir, 20 veces o más).
A continuación, en la figura, se ilustra este comportamiento utilizando la consola del navegador:
El código utilizado para cargar y usar texturas es el siguiente:
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
});
};
Para fines de depuración, también puede encontrar una vista previa en vivo aquí: https://alexprut.github.io/earth-defender/ y el código del juego aquí: https://github.com/alexprut/earth-defender/tree/master/ cliente / js
[x] r80
[x] Todos ellos
[ ] Explorador de Internet
[x] Todos ellos
Creo que el cargador está funcionando de la forma prevista. Está cargando las texturas del meteorito 200 veces porque usted se lo pide. El cargador podría modificarse para almacenar en caché y devolver automáticamente los activos que le pida que cargue varias veces, pero es posible que esto no sea necesario en todos los casos. El navegador administrará el caché, por lo que si todos los encabezados del archivo de imagen son correctos, el navegador devolverá versiones en caché de la imagen cada vez.
En tu código:
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)
);
};
Consideraría agregar algo como lo siguiente:
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;
};
Por lo tanto, administra un caché de materiales que se cargan desde una matriz en lugar de regenerarse cada vez. Esto funcionará bien si todos los asteroides tienen el mismo material, o use el método .clone () si desea que los materiales sean diferentes.
Vea si eso ayuda.
@calrk agradece que resuelve el problema.
Sigo creyendo que THREE.TextureLoader()
comporta de una manera inesperada, debería preguntarte si quieres almacenar en caché o no las texturas, por ejemplo:
var loader = THREE.TextureLoader();
loader(texture, cache = false);
Creo que, de forma predeterminada, el cargador debería almacenar en caché las texturas por razones de rendimiento (si me equivoco, avíseme por qué).
A continuación se muestra un módulo de caché de solución simple (patrón Singleton / Patrón de módulo):
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
}
})();
Para usar y almacenar en caché la textura, debe llamar a:
TextureLoader.getInstance().load(texture);
XHRLoader
que se llama desde TextureLoader
través de ImageLoader
usa el objeto global Cache
pero el valor predeterminado Cache.enabled
es false
.
Si configura THREE.Cache.enabled = true;
justo después de cargar three.js
funcionaría.
Comentario más útil
XHRLoader
que se llama desdeTextureLoader
través deImageLoader
usa el objeto globalCache
pero el valor predeterminado
Cache.enabled
esfalse
.Si configura
THREE.Cache.enabled = true;
justo después de cargarthree.js
funcionaría.
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