kne*_*ola 5 javascript multithreading textures web-worker three.js
当将大纹理图像应用到网格上一段明显的时间时,Three.js 会锁定浏览器的主线程。让我们考虑以下示例:
var texLoader = new THREE.TextureLoader();
texLoader.load('someLargeTexture.jpg', function(texture) {
var geometry = new THREE.SphereGeometry(10, 32, 32);
var material = new THREE.MeshBasicMaterial({map: texture});
var sphere = new THREE.Mesh(geometry, material);
// adding the object to the scene will lock up the browser's main thread
scene.add(sphere);
});
Run Code Online (Sandbox Code Playgroud)
我还注意到以下几点:
我的结论是,Three.js 在材质添加到场景时对其进行了一些处理。结果被缓存并稍后重新使用。
问题是这项工作是否可以以某种方式卸载给 Web Worker,这样主线程就不会被锁定?
工人可能看起来像这样:
var texLoader = new THREE.TextureLoader();
texLoader.load('someLargeTexture.jpg', function(texture) {
var material = new THREE.MeshBasicMaterial({map: texture});
// ... long-running work goes here ...
// adding the object to the scene will lock up the browser's main thread
self.postMessage({
msg: 'objectCreated',
material: material.toJson(), // converting material to JSON
});
});
Run Code Online (Sandbox Code Playgroud)
然后在主线程中我们可以这样做:
var worker = new Worker('worker.js');
worker.addEventListener('message', function(ev) {
var geometry = new THREE.SphereGeometry(10, 32, 32);
// converting JSON back to material object
var material = MaterialLoader.prototype.parse( ev.data.material );
// this should't lock-up the main thread
var sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
});
Run Code Online (Sandbox Code Playgroud)
这样的事情可以做吗?
只是在尝试与工作人员并行加载纹理时遇到这个问题。主要障碍似乎是三个。Texture 保存对 <img> (DOM 元素)的引用,而 <img> 又保存实际的图像数据。不知道如何序列化 <img>,webgl 也接受 <img> 作为纹理数据。所以三人没必要碰它。
解决方案可能是使用 THREE.DataTexture,但这涉及将可能压缩的图像转换为未压缩的 RGB。不幸的是,通过 <canvas> drawImage() + getImageData() 绕道是不可能的,因为工作人员无法处理 DOM 元素。
最终我决定并行纹理加载必须等待-offscreen-canvas-interface。