问题
When applying a large texture image to a Mesh for a noticeable period of time Three.js locks-up browser's main thread. Let's consider the following example:
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);
});
I also noticed the following:
- no thread lock-up occurs if the new object is not added to the scene
- changing the geometry of an object doesn't cause lock-up
- if a new object is created with a material borrowed from an existing object (which already is in the scene) will will not cause lock-up
- assigning a new material to an existing object (which already is in the scene) will causes lock-up
My conclusion is that Three.js does some work on a material at point at which it's added to the scene. The result is the cached and later re-used.
The question is if this work can somehow be offloaded to web worker, so that the main thread doesn't get locked-up?
The worker could look like this:
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
});
});
Then in the main thread we could do:
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);
});
Can something like this be done?
回答1:
Just run into this issue while trying to load textures in parallel with workers. Main roadblock seems to be THREE.Texture holds a reference to the <img> (DOM element) which in turn holds the actual image data. Don't know of a way to serialize an <img>, also webgl accepts <img> as texture data. So there is no need for THREE to touch it.
A solution might be to use a THREE.DataTexture, but that involves turning possibly compressed images into uncompressed RGB. Unfortunately a detour via a <canvas> drawImage() + getImageData() is not possible, because workers can't deal with DOM elements.
Eventually I've decided parallel texture loading has to wait for the-offscreen-canvas-interface.
来源:https://stackoverflow.com/questions/43341757/loading-texture-from-web-worker-in-three-js