Angular или Three.js не тянут изображение с сервера, а скорее кеш браузера

0

Пожалуйста, ознакомьтесь с обновлением 3 в конце этого сообщения для самой последней активности/плунжера

Я использую AngularJS поверх приложения Node/Express. В этом приложении я использую three.js для отображения 3D-объекта. Текстура, которая обертывает этот объект, изменяется, но имя файла не изменяется (например, цвет изображения текстуры изменяется, но имя файла остается Texture_0.png).

Файл текстуры хранится в хранилище Azure Blob, и у меня есть CORS, поэтому он отображается правильно. Если я обновляю изображение и загружаю его в хранилище Azure Blob в новом сеансе, при первом рендеринге моего 3D-объекта он отображает текстуру с ее изменениями. Тем не менее, в любое время, когда я загружаю новые изменения и пытаюсь повторно отобразить его, отображается изображение в кэше браузера вместо нового изображения, которое хранится и ссылается на сервере. Для просмотра изменений требуется обновление страницы, но мне нужно, чтобы это отображалось, когда я нажимаю кнопку, которая появляется модально, а не обновление страницы.

Как заставить AngularJS отображать серверную версию текстурного изображения вместо кеша браузера без обновления моей страницы?

Я попытался добавить некоторую случайную математику, чтобы заставить браузер загружаться с сервера, но он не работает. Соответствующий код выглядит следующим образом:

Код объекта 3D.JS:

$scope.generate3D = function () {

// 3D OBJECT - Variables
var texture0 = baseBlobURL + 'Texture_0.png?' + Math.random();
var boxDAE = baseBlobURL + 'Box.dae?' + Math.random();
var scene;
var camera;
var renderer;
var box;
var controls;
var newtexture;


// 3D OBJECT - Generate  

newtexture = THREE.ImageUtils.loadTexture(texture0);

//Instantiate a Collada loader
var loader = new THREE.ColladaLoader();

loader.options.convertUpAxis = true;
loader.load(boxDAE, function (collada) {

box = collada.scene;

box.traverse(function (child) {

if (child instanceof THREE.SkinnedMesh) {

var animation = new THREE.Animation(child, child.geometry.animation);
animation.play();

}
});

box.scale.x = box.scale.y = box.scale.z = .2;
box.updateMatrix();

init();
animate();
});

function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer();

renderer.setClearColor(0xdddddd);

renderer.setSize(500, 500);

// Load the box file
scene.add(box);

// Lighting
var light = new THREE.AmbientLight();
scene.add(light);

// Camera
camera.position.x = 40;
camera.position.y = 40;
camera.position.z = 40;

camera.lookAt(scene.position);

// Rotation Controls
controls = new THREE.OrbitControls(camera, renderer.domElement);

controls.rotateSpeed = 5.0;
controls.zoomSpeed = 5;

controls.noZoom = false;
controls.noPan = false;

var myEl = angular.element(document.querySelector('#webGL-container'));
myEl.append(renderer.domElement);

}

function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);               
}
}

Угловая функция для вызова 3D-объекта и поп-музыки в модальном режиме:

$scope.boxPreview = function () {
$scope.generate3D();
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: 'lg'
}

Модально встроено как тег сценария (мне нужно это в представлении, поскольку URL-адреса изображений уникальны, а код для запуска моего представления нуждается в этих переменных, а также в трехмерном объектном коде):

<script type="text/ng-template" id="myModalContent.html">
    <div class="modal-header">
        <h3 class="modal-title">Box Preview</h3>
    </div>
    <div class="modal-body">

        <div id="webGL-container" width="500px">
        </div>

    </div>
    <div class="modal-footer">
        <button class="btn btn-primary" data-ng-click="ok()">Close</button>
    </div>
</script>

Обновление 1:

Когда вы просматриваете вкладку сети в Chrome, я вижу, что она сбрасывает правильное изображение, но просто не показывает его в Modal. Я попытался отключить кеш, но это не повлияло. Это похоже на three.js где-то держит изображение... но я просто не знаю, как его очистить.

Обновление 2:

Используя рекомендации Mr.doob, перечисленные в этом сообщении, я могу заставить его перезагрузить без обновления страницы один раз, прежде чем я получу следующую ошибку:

RangeError: превышен максимальный размер стека вызовов

Когда я добавляю следующий код, где я создаю экземпляр моего загрузчика:

THREE.ImageLoader.prototype._load = THREE.ImageLoader.prototype.load;
THREE.ImageLoader.prototype.load = function (url, onLoad, onProgress, onError) {
this._load(url + '?' + Math.random(), onLoad, onProgress, onError);
};

//Instantiate a Collada loader
var loader = new THREE.ColladaLoader();

Вот последовательность событий:

1) При первом нажатии, чтобы отобразить 3D-окно в новом сеансе, отображаются изменения

2) Измените текстуру и загрузите ее, затем нажмите, чтобы показать 3D-окно в том же сеансе, и отобразите изменения. Раньше он не показывался, пока страница не была обновлена.

3) Измените текстуру и загрузите ее, затем нажмите, чтобы показать окно 3D в том же сеансе. RangeError: превышен максимальный размер стека вызовов

Чтобы быть ясным, я открываю это в Модале. и видели проблемы с модулями, которые генерируют эти ошибки, но я сохраняю только один вызов контроллера на уровне маршрутизации.

ОБНОВЛЕНИЕ 3:

Я собрал следующий плунж:

http://plnkr.co/edit/DGZA9LUBZWsLWrmXaaKD

Для получения изображений используется моя общая папка dropbox. Я получаю ту же проблему, где, если я перезаписываю файл текстуры, он не обновляется, когда я выбираю предварительный просмотр окна, если я не обновляю страницу. Мне нужно это, чтобы обновить текстуру окна при щелчке. Несколько критических замечаний:

1) Я консоль регистрировал термин "загруженный", чтобы показать, что это продолжает отображаться даже после закрытия модала. Я не уверен, что мне нужно постоянно визуализировать/анимацию, так как мне просто нужно вращать коробку с помощью OrbitControls. Пожалуйста, дайте мне знать, если есть лучший способ, или если это вызывает проблему кеширования/нам нужно уничтожить сцену/воссоздать ее для обновления окна

2) Используя код, рекомендованный Mr.Doob, я могу обновить изображение на сервере и повторно обработать его один раз, прежде чем он даст мне ошибку:

Uncaught RangeError: превышен максимальный размер стека вызовов

Вот код:

THREE.ImageLoader.prototype._load = THREE.ImageLoader.prototype.load;
            THREE.ImageLoader.prototype.load = function (url, onLoad, onProgress, onError) {
               this._load(url + '?' + Math.random(), onLoad, onProgress, onError);
           };

Я оставил этот код на месте, так как он достиг того, чего я хотел хотя бы раз перед сбоем.

3) Поскольку мы используем общедоступный Dropbox, я не уверен, что те, кто помогает мне, смогут перезаписать файл Texture_0.png с изменениями (я открыл его в краске и просто пропустил некоторые вещи на нем и повторно загрузил в Dropbox), но вы можете изменить URL-адрес на свой собственный Dropbox для тестирования, так как у вас будет возможность загрузить и увидеть, что текстура окна не обновляется, если вы не перезагрузите веб-страницу (plunker).

  • 0
    код, связанный с третьим лицом, принадлежит директиве
  • 0
    Любое руководство о том, как поместить это в директиву? Это решит проблему кеширования браузера? Немного сложно в том, что код на этой странице получает переменные, передаваемые ему из параметров маршрута, чтобы определить путь URL для изображений. Есть ли не директивный вариант?
Показать ещё 5 комментариев
Теги:
azure
three.js
browser-cache

2 ответа

2
Лучший ответ

Если вы редактируете файл изображения позади трех.js и не изменяете имя файла, и хотите обновить текстуру материала, вы можете использовать шаблон, подобный этому:

mesh.material.map.dispose(); // unrelated, but important!
mesh.material.map = THREE.ImageUtils.loadTexture( "filename.jpg" + "?" + Math.random() );

Если цикл анимации отсутствует, вам необходимо принудительно выполнить повторную визуализацию, например:

mesh.material.map.dispose(); // unrelated, but important!
mesh.material.map = THREE.ImageUtils.loadTexture( "filename.jpg" + "?" + Math.random(), undefined, render );

three.js r.72

  • 0
    В моем текущем коде three.js я не определил меш. Как бы я включил это в мой код?
  • 0
    Будет ли моя текстура материалом? Файл Collada, загружаемый загрузчиком Collada, ссылается на файлы .png.
Показать ещё 22 комментария
0

Ответ @weslangley технически корректен для большинства пользователей three.js, поскольку они используют материалы. В моем очень уникальном случае у меня есть отличный файл Collada, где мне пришлось отредактировать файл ImageLoader.js, чтобы он мог вернуть файл изображения с тем же именем файла (но с другим изображением) на лету с сервера. Я не рекомендую касаться исходного кода, но в моем случае я добавил следующую строку под функцией загрузки с помощью ImageLoader.js:

url = url + '?' + Math.random();

Для меня это сработало, но опять же, для 99,9% других пользователей из трех. Js это, скорее всего, не применимо.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню