Skip to content

Commit

Permalink
OBJLoader web worker wrapper (mrdoob#9756)
Browse files Browse the repository at this point in the history
WWOBJLoaderFrontEnd.js:
Handles mtl loading via MTLLoader. Materials are passed without textures to WWOBJLoader. Webworker (WWOBJLoader.js) re-creates the MaterialCreator.
It can be used with both files and already loaded files (arraybuffer/string) and pass the obj data to the webworker (arraybuffer is useful when OBJ file was for example stored in zip).
Realizes the communication and workflow with the webworker.

WWOBJLoader.js:
Is an extension of OBJLoader and wraps it into a web worker. It overrides the '_buildSingleMesh' method. Sending back the mesh content to WWOBJLoaderFrontEnd.js

WWCommons.js:
Relative import paths for webworker defined outside. Possibility to share other common static information
  • Loading branch information
Kai Salmen committed Sep 23, 2016
1 parent 151f57b commit 4335c25
Show file tree
Hide file tree
Showing 3 changed files with 626 additions and 0 deletions.
23 changes: 23 additions & 0 deletions examples/js/loaders/webworker/WWCommons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* @author Kai Salmen / www.kaisalmen.de
*/

'use strict';

if ( THREE === undefined ) {
var THREE = {}
}

if ( THREE.WebWorker === undefined ) {

THREE.WebWorker = {
Commons: {
paths: {
threejsPath: '../../../../build/three.min.js',
objLoaderPath: '../OBJLoader.js',
mtlLoaderPath: '../MTLLoader.js'
}
}
}

}
220 changes: 220 additions & 0 deletions examples/js/loaders/webworker/WWOBJLoader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/**
* @author Kai Salmen / www.kaisalmen.de
*/

'use strict';

importScripts( './WWCommons.js' );
importScripts( THREE.WebWorker.Commons.paths.threejsPath );
importScripts( THREE.WebWorker.Commons.paths.objLoaderPath );
importScripts( THREE.WebWorker.Commons.paths.mtlLoaderPath );

THREE.WebWorker.WWOBJLoader = (function () {

WWOBJLoader.prototype = Object.create( THREE.OBJLoader.prototype, {
constructor: {
configurable: true,
enumerable: true,
value: WWOBJLoader,
writable: true
}
} );

function WWOBJLoader() {
THREE.OBJLoader.call( this );
this.cmdState = 'created';
this.debug = false;

this.basePath = '';
this.objFile = '';
this.dataAvailable = false;
this.objAsArrayBuffer = null;

this.setLoadAsArrayBuffer( true );
this.setWorkInline( true );

this.counter = 0;
}

WWOBJLoader.prototype._buildSingleMesh = function ( object, material ) {
// Fast-Fail: Skip o/g line declarations that did not follow with any faces
if ( object.geometry.vertices.length === 0 ) return null;

this.counter ++;

var geometry = object.geometry;
var objectMaterials = object.materials;

var verticesOut = new Float32Array( geometry.vertices );
var normalsOut = null;
if ( geometry.normals.length > 0 ) {

normalsOut = new Float32Array( geometry.normals );

}
var uvsOut = new Float32Array( geometry.uvs );


var materialGroups = [];
var materialNames = [];
var multiMaterial = false;
if ( material instanceof THREE.MultiMaterial ) {

for ( var objectMaterial, group, i = 0, length = objectMaterials.length; i < length; i ++ ) {

objectMaterial = objectMaterials[ i ];
group = {
start: objectMaterial.groupStart,
count: objectMaterial.groupCount,
index: i
};
materialGroups.push( group );

}

var mMaterial;
for ( var key in material.materials ) {

mMaterial = material.materials[ key ];
materialNames.push( mMaterial.name );

}
multiMaterial = true;
}


self.postMessage( {
cmd: 'objData',
meshName: object.name,
multiMaterial: multiMaterial,
materialName: multiMaterial ? JSON.stringify( materialNames ) : material.name,
materialGroups: multiMaterial ? JSON.stringify( materialGroups ) : null,
vertices: verticesOut,
normals: normalsOut,
uvs: uvsOut,
}, [ verticesOut.buffer ], [ normalsOut.buffer ], [ uvsOut.buffer ] );

return null;
};


WWOBJLoader.prototype.init = function ( payload ) {
this.cmdState = 'init';

this.debug = payload.debug;
this.dataAvailable = payload.dataAvailable;
this.basePath = payload.basePath === null ? '' : payload.basePath;
this.objFile = payload.objFile === null ? '' : payload.objFile;

// configure OBJLoader
if ( payload.loadAsArrayBuffer !== undefined ) {

this.setLoadAsArrayBuffer( payload.loadAsArrayBuffer );

}
if ( payload.workInline !== undefined ) {

this.setWorkInline( payload.workInline );

}
this.setPath( this.basePath );

if ( this.dataAvailable ) {

// this must be the case, otherwise loading will fail
this.setLoadAsArrayBuffer( true );
this.objAsArrayBuffer = payload.objAsArrayBuffer;

}
};

WWOBJLoader.prototype.initMaterials = function ( payload ) {
this.cmdState = 'initMaterials';

var materialsJSON = JSON.parse( payload.materials );
var materialCreator = new THREE.MTLLoader.MaterialCreator( payload.baseUrl, payload.options );
materialCreator.setMaterials( materialsJSON );
materialCreator.preload();

this.setMaterials( materialCreator );
};

WWOBJLoader.prototype.run = function () {
this.cmdState = 'run';
var scope = this;

var complete = function () {
console.log( 'OBJ loading complete!' );

scope.cmdState = 'complete';
self.postMessage( {
cmd: scope.cmdState
} );

scope.dispose();
};

if ( scope.dataAvailable ) {

scope.parseArrayBuffer( scope.objAsArrayBuffer );
complete();

} else {

var onLoad = function () {
complete();
};

var onProgress = function ( xhr ) {
if ( xhr.lengthComputable ) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log( Math.round( percentComplete, 2 ) + '% downloaded' );
}
};

var onError = function ( xhr ) {
console.error( xhr );
};

scope.load( scope.objFile, onLoad, onProgress, onError );

}
};

return WWOBJLoader;
})();

var implRef = new THREE.WebWorker.WWOBJLoader( this );

var runner = function ( event ) {
var payload = event.data;

console.log( 'Command state before: ' + implRef.cmdState );

switch ( payload.cmd ) {
case 'init':

implRef.init( payload );
break;

case 'initMaterials':

implRef.initMaterials( payload );
break;

case 'run':

implRef.run();
break;

default:

console.error( 'WWOBJLoader: Received unknown command: ' + payload.cmd );
break;

}

console.log( 'Command state after: ' + implRef.cmdState );
};

self.addEventListener( 'message', runner, false );
Loading

0 comments on commit 4335c25

Please sign in to comment.