在Three.js中从Web Worker加载纹理

5

当将大型纹理图像应用于网格并保持一段时间时,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中,以使主线程不会被锁定?
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的地方,那么除了使用较小的纹理或将其分割成几个材质之外,可能没有其他办法可供你采取。 - TheJim01
1个回答

2

在尝试使用工作线程并行加载纹理时,遇到了这个问题。主要障碍似乎是THREE.Texture保留对<img>(DOM元素)的引用,而<img>又保存实际图像数据。不知道如何序列化<img>,同时webgl接受<img>作为纹理数据,所以THREE没有必要去处理它。

一个解决方法可能是使用THREE.DataTexture,但这涉及将可能被压缩的图像转换为未压缩的RGB。不幸的是,通过<canvas> drawImage() + getImageData()的绕路不可能,因为工作线程无法处理DOM元素。

最终,我决定并行纹理加载必须等待离屏画布接口


也许 https://github.com/spite/THREE.UpdatableTexture 和 https://github.com/mrdoob/three.js/pull/11846 会引起您的兴趣? - WestLangley
@WestLangley,确实等不及了r87。 - Torsten Becker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接