2017-04-11 5 views
1

Lors de l'application d'une grande image de texture à un filet pour une période de temps notable Three.js fil principal se bloque navigateur. Prenons l'exemple suivant:texture Chargement de Web Worker dans 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); 
}); 

J'ai aussi remarqué ce qui suit:

  • pas de lock-up de fil se produit si le nouvel objet n'est pas ajouté à la scène
  • changer la géométrie un objet ne provoque pas de lock-up
  • si un nouvel objet est créé avec un matériau emprunté à un objet existant (ce qui est déjà dans la scène) va ne causera lock-up
  • attribuer un nouveau matériau à un objet existant (ce qui est déjà dans la scène) provoque la volonté de lock-up

Ma conclusion est que Three.js fait un travail sur un matériau à point auquel il est ajouté à la scène. Le résultat est le cache et réutilisé plus tard.

La question est de savoir si ce travail peut en quelque sorte être débarquée au travailleur Web, de sorte que le thread principal ne soit pas verrouillé-up?

Le travailleur pourrait ressembler à ceci:

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 
    }); 
}); 

Ensuite, dans le fil conducteur que nous pourrions faire:

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); 
}); 

Peut-être quelque chose comme ça fait?

+0

Vous pouvez utiliser les outils de débogage du navigateur pour prendre un instantané de la chronologie de cette opération de chargement. Par exemple, dans Chrome, vous verrez la méthode X prenant Y secondes. Cela devrait vous montrer où est le goulot d'étranglement. Si c'est là que THREE.js envoie la texture au GPU, il se peut que vous ne puissiez rien faire d'autre que d'utiliser une texture plus petite ou de la diviser en plusieurs matériaux. – TheJim01

Répondre

1

Il suffit de lancer ce problème en essayant de charger des textures en parallèle avec les travailleurs. Le roadblock principal semble être TROIS.Texture contient une référence au <img> (élément DOM) qui à son tour contient les données d'image réelles. Ne pas connaître un moyen de sérialiser un <img>, également . Donc, il n'y a pas besoin de TROIS pour le toucher.

Une solution pourrait être d'utiliser un THREE.DataTexture, mais qui consiste à transformer des images éventuellement compressés en RVB non compressé. Malheureusement, un détour via un <canvas> drawImage() + getImageData() n'est pas possible, car les travailleurs ne peuvent pas gérer les éléments DOM.

Finalement, j'ai décidé de chargement texture parallèle doit attendre the-offscreen-canvas-interface.

+0

Peut-être que https://github.com/spite/THREE.UpdatableTexture et https://github.com/mrdoob/three.js/pull/11846 seraient d'intérêt? – WestLangley

+0

@WestLangley, en effet ne peut pas attendre r87. – noiv