THREE.TextureLoader () ведет себя неожиданным и ошибочным образом. Функция load () класса пытается / загружает одни и те же ресурсы несколько раз (т.е. 20 раз или больше).
На рисунке ниже показано это поведение с помощью консоли браузера:
Код, используемый для загрузки и использования текстур, следующий:
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
});
};
В целях отладки вы также можете найти предварительный просмотр здесь: https://alexprut.github.io/earth-defender/ и код игры здесь: https://github.com/alexprut/earth-defender/tree/master/ клиент / js
[x] r80
[x] Все они
[] Internet Explorer
[x] Все они
Я считаю, что загрузчик работает по назначению. Он загружает текстуры метеора 200 раз, потому что вы об этом просите. Загрузчик можно изменить для автоматического кэширования и возврата ресурсов, которые вы просите загрузить несколько раз, но это может потребоваться не во всех случаях. Браузер будет управлять кешем, поэтому, если все заголовки в файле изображения верны, браузер каждый раз будет возвращать кешированные версии изображения.
В вашем коде:
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)
);
};
Я бы подумал добавить что-то вроде следующего:
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;
};
Таким образом, вы управляете кешем материалов, которые загружаются из массива, а не регенерируются каждый раз. Это будет хорошо работать, если все астероиды имеют одинаковый материал, или используйте метод .clone (), если вы хотите, чтобы материалы были разными.
Посмотрим, поможет ли это.
@calrk спасибо, это решает проблему.
Я все еще считаю, что THREE.TextureLoader()
ведет себя неожиданным образом, он должен спросить вас, хотите ли вы кэшировать текстуры, например:
var loader = THREE.TextureLoader();
loader(texture, cache = false);
Я думаю, что по умолчанию загрузчик должен кэшировать текстуры из соображений производительности (если я ошибаюсь, дайте мне знать, почему).
Ниже приведено простое решение (шаблон синглтона / шаблон модуля) кеш-модуля:
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
}
})();
Для использования и кеширования текстуры вам необходимо вызвать:
TextureLoader.getInstance().load(texture);
XHRLoader
который вызывается из TextureLoader
через ImageLoader
использует глобальный объект Cache
но по умолчанию Cache.enabled
- это false
.
Если вы установите THREE.Cache.enabled = true;
сразу после загрузки three.js
это сработает.
Самый полезный комментарий
XHRLoader
который вызывается изTextureLoader
черезImageLoader
использует глобальный объектCache
но по умолчанию
Cache.enabled
- этоfalse
.Если вы установите
THREE.Cache.enabled = true;
сразу после загрузкиthree.js
это сработает.
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