Angular或Three.js不会从服务器中提取图像,而是从浏览器缓存中提取图像
Angular or Three.js not pulling image from server, but rather browser cache
请参阅本文末尾的更新3获取最新活动/plunker
我在Node/Express应用程序上使用AngularJS。在这个应用程序中,我使用three.js来显示一个3D对象。包装该对象的纹理会改变,但文件名不会改变(例如,纹理图像的颜色会改变,但文件名仍然是Texture_0.png)。
纹理文件存储在Azure Blob Storage中,我启用了CORS,因此它可以正确显示。如果我在一个新的会话中更新一个图像并将其上传到Azure Blob Storage,那么我第一次渲染我的3D对象时,它会显示纹理的变化。但是,每当我上传新的更改并尝试重新渲染时,它都会显示浏览器缓存的图像,而不是存储在服务器中并引用的新图像。需要刷新页面才能看到更改,但我需要在单击弹出模式的按钮时显示此更改,而不是页面刷新。
如何让AngularJS显示服务器版本的纹理图像而不是浏览器缓存而不刷新我的页面?
我已经尝试添加一些随机数学来强制浏览器从服务器下载,但它不工作。相关代码如下:
Three.JS 3D Object Code:
$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 Object和Pop in Modal的Angular函数:
$scope.boxPreview = function () {
$scope.generate3D();
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: 'lg'
}
模态嵌入作为一个脚本标签(我需要这个在视图中,因为图像url是唯一的,代码运行我的视图需要这些变量以及3D对象代码):
<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: Maximum call stack size exceeded
当我在实例化加载器的地方添加以下代码时:
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: Maximum call stack size exceeded
代码如下:
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)。
如果你正在编辑three.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
@weslangley回答对于three.js的大多数用户来说在技术上是正确的,因为他们使用的是材料。在我非常独特的情况下,我有一个独特的Collada文件,我必须编辑ImageLoader.js文件,以便让它从服务器上动态返回具有相同文件名(但不同图像内容)的图像文件。我不建议触摸源代码,但在我的情况下,我在ImageLoader.js中的load函数下添加了以下行:
url = url + '?' + Math.random();
对于我来说,这是有效的,但是对于three.js的99.9%的其他用户来说,这可能不适用。
- 使用javascript从HTML网页中提取图像url
- 是否可以创建一个画布来提取图像数据,而无需实际渲染画布
- 我可以使用 javascript 从类别中提取图像吗?
- 使用 AngularJS 从
RSS 提要中提取图像 - 提取图像src并使其成为另一个图像的src
- 当源是IE/EDGE上的加密令牌视频时,Canvas未从azure媒体播放器中提取图像
- 如何使用动力学JS从其他图像中提取图像
- 从9GAG中提取图像
- 我需要什么类型的正则表达式来从markdown中提取图像url
- Jquery.backstretch.min.js从数据库或变量中提取图像
- 使用Javascript从HTML代码中提取图像url
- 使用PDFJS从单个PDF页面提取图像
- 如何使用jQuery从字符串中提取图像标签
- 从远程源Javascript中提取图像
- 从网页中提取图像源,其中img标签可能会在使用javascript etcq渲染页面时添加
- Angular或Three.js不会从服务器中提取图像,而是从浏览器缓存中提取图像
- 如何从数组中提取图像并放入列表中
- 如何创建Adobe Air应用程序,从应用程序外的计算机上的文件夹中提取图像
- Regex从xml中提取图像
- 从API中提取图像