【发布时间】:2017-09-06 14:16:09
【问题描述】:
当在很长一段时间内将大型纹理图像应用于 Mesh 时,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);
});
我还注意到以下几点:
- 如果新对象未添加到场景中,则不会发生线程锁定
- 更改对象的几何形状不会导致锁定
- 如果使用从现有对象(已在场景中)借用的材质创建新对象,将不会导致锁定
- 将新材质分配给现有对象(已在场景中)将导致锁定
我的结论是 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
});
});
然后在主线程中我们可以这样做:
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);
});
这样的事情可以做吗?
【问题讨论】:
-
您可以使用浏览器调试工具对该加载操作进行时间线快照。例如,在 Chrome 中,您会看到方法 X 需要 Y 秒。这应该告诉你瓶颈在哪里。如果它是 THREE.js 将纹理发送到 GPU 的地方,那么您可能无能为力,只能使用较小的纹理,或者将其拆分为多个材质。
标签: javascript multithreading three.js textures web-worker