【问题标题】:Loading texture from Web Worker in Three.js在 Three.js 中从 Web Worker 加载纹理
【发布时间】: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


【解决方案1】:

在尝试与工作线程并行加载纹理时遇到了这个问题。主要障碍似乎是 THREE.Texture 包含对 (DOM 元素)的引用,而后者又包含实际的图像数据。不知道序列化 的方法,还有webgl accepts <img> as texture data。所以没有必要让三个人去碰它。

一种解决方案可能是使用 THREE.DataTexture,但这涉及将可能压缩的图像转换为未压缩的 RGB。不幸的是,通过 drawImage() + getImageData() 绕道是不可能的,因为工人无法处理 DOM 元素。

最终我决定并行纹理加载必须等待the-offscreen-canvas-interface

【讨论】:

猜你喜欢
  • 2016-10-11
  • 2013-06-28
  • 2015-05-30
  • 2014-03-10
  • 1970-01-01
  • 1970-01-01
  • 2013-07-28
  • 2012-10-03
  • 2014-12-28
相关资源
最近更新 更多