SceneLoader.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. /**
  2. * @author alteredq / http://alteredqualia.com/
  3. */
  4. THREE.SceneLoader = function () {
  5. this.onLoadStart = function () {};
  6. this.onLoadProgress = function() {};
  7. this.onLoadComplete = function () {};
  8. this.callbackSync = function () {};
  9. this.callbackProgress = function () {};
  10. };
  11. THREE.SceneLoader.prototype = {
  12. load : function ( url, callbackFinished ) {
  13. var scope = this;
  14. var worker = new Worker( url );
  15. worker.postMessage( 0 );
  16. var urlBase = THREE.Loader.prototype.extractUrlbase( url );
  17. worker.onmessage = function( event ) {
  18. var dg, dm, dd, dl, dc, df, dt,
  19. g, o, m, l, p, c, t, f, tt, pp,
  20. geometry, material, camera, fog,
  21. texture, images,
  22. materials, light,
  23. data, binLoader, jsonLoader,
  24. counter_models, counter_textures,
  25. total_models, total_textures,
  26. result;
  27. data = event.data;
  28. binLoader = new THREE.BinaryLoader();
  29. jsonLoader = new THREE.JSONLoader();
  30. counter_models = 0;
  31. counter_textures = 0;
  32. result = {
  33. scene: new THREE.Scene(),
  34. geometries: {},
  35. materials: {},
  36. textures: {},
  37. objects: {},
  38. cameras: {},
  39. lights: {},
  40. fogs: {},
  41. triggers: {},
  42. empties: {}
  43. };
  44. // find out if there are some colliders
  45. var hasColliders = false;
  46. for( dd in data.objects ) {
  47. o = data.objects[ dd ];
  48. if ( o.meshCollider ) {
  49. hasColliders = true;
  50. break;
  51. }
  52. }
  53. if ( hasColliders ) {
  54. result.scene.collisions = new THREE.CollisionSystem();
  55. }
  56. if ( data.transform ) {
  57. var position = data.transform.position,
  58. rotation = data.transform.rotation,
  59. scale = data.transform.scale;
  60. if ( position )
  61. result.scene.position.set( position[ 0 ], position[ 1 ], position [ 2 ] );
  62. if ( rotation )
  63. result.scene.rotation.set( rotation[ 0 ], rotation[ 1 ], rotation [ 2 ] );
  64. if ( scale )
  65. result.scene.scale.set( scale[ 0 ], scale[ 1 ], scale [ 2 ] );
  66. if ( position || rotation || scale )
  67. result.scene.updateMatrix();
  68. }
  69. function get_url( source_url, url_type ) {
  70. if ( url_type == "relativeToHTML" ) {
  71. return source_url;
  72. } else {
  73. return urlBase + "/" + source_url;
  74. }
  75. };
  76. function handle_objects() {
  77. for( dd in data.objects ) {
  78. if ( !result.objects[ dd ] ) {
  79. o = data.objects[ dd ];
  80. if ( o.geometry !== undefined ) {
  81. geometry = result.geometries[ o.geometry ];
  82. // geometry already loaded
  83. if ( geometry ) {
  84. var hasNormals = false;
  85. materials = [];
  86. for( i = 0; i < o.materials.length; i++ ) {
  87. materials[ i ] = result.materials[ o.materials[i] ];
  88. hasNormals = materials[ i ] instanceof THREE.MeshShaderMaterial;
  89. }
  90. if ( hasNormals ) {
  91. geometry.computeTangents();
  92. }
  93. p = o.position;
  94. r = o.rotation;
  95. q = o.quaternion;
  96. s = o.scale;
  97. // turn off quaternions, for the moment
  98. q = 0;
  99. if ( materials.length == 0 ) {
  100. materials[ 0 ] = new THREE.MeshFaceMaterial();
  101. }
  102. // dirty hack to handle meshes with multiple materials
  103. // just use face materials defined in model
  104. if ( materials.length > 1 ) {
  105. materials = [ new THREE.MeshFaceMaterial() ];
  106. }
  107. object = new THREE.Mesh( geometry, materials );
  108. object.name = dd;
  109. object.position.set( p[0], p[1], p[2] );
  110. if ( q ) {
  111. object.quaternion.set( q[0], q[1], q[2], q[3] );
  112. object.useQuaternion = true;
  113. } else {
  114. object.rotation.set( r[0], r[1], r[2] );
  115. }
  116. object.scale.set( s[0], s[1], s[2] );
  117. object.visible = o.visible;
  118. result.scene.addObject( object );
  119. result.objects[ dd ] = object;
  120. if ( o.meshCollider ) {
  121. var meshCollider = THREE.CollisionUtils.MeshColliderWBox( object );
  122. result.scene.collisions.colliders.push( meshCollider );
  123. }
  124. if ( o.castsShadow ) {
  125. //object.visible = true;
  126. //object.materials = [ new THREE.MeshBasicMaterial( { color: 0xff0000 } ) ];
  127. var shadow = new THREE.ShadowVolume( geometry )
  128. result.scene.addChild( shadow );
  129. shadow.position = object.position;
  130. shadow.rotation = object.rotation;
  131. shadow.scale = object.scale;
  132. }
  133. if ( o.trigger && o.trigger.toLowerCase() != "none" ) {
  134. var trigger = {
  135. "type" : o.trigger,
  136. "object" : o
  137. };
  138. result.triggers[ object.name ] = trigger;
  139. }
  140. }
  141. // pure Object3D
  142. } else {
  143. p = o.position;
  144. r = o.rotation;
  145. q = o.quaternion;
  146. s = o.scale;
  147. // turn off quaternions, for the moment
  148. q = 0;
  149. object = new THREE.Object3D();
  150. object.name = dd;
  151. object.position.set( p[0], p[1], p[2] );
  152. if ( q ) {
  153. object.quaternion.set( q[0], q[1], q[2], q[3] );
  154. object.useQuaternion = true;
  155. } else {
  156. object.rotation.set( r[0], r[1], r[2] );
  157. }
  158. object.scale.set( s[0], s[1], s[2] );
  159. object.visible = ( o.visible !== undefined ) ? o.visible : false;
  160. result.scene.addObject( object );
  161. result.objects[ dd ] = object;
  162. result.empties[ dd ] = object;
  163. if ( o.trigger && o.trigger.toLowerCase() != "none" ) {
  164. var trigger = {
  165. "type" : o.trigger,
  166. "object" : o
  167. };
  168. result.triggers[ object.name ] = trigger;
  169. }
  170. }
  171. }
  172. }
  173. };
  174. function handle_mesh( geo, id ) {
  175. result.geometries[ id ] = geo;
  176. handle_objects();
  177. };
  178. function create_callback( id ) {
  179. return function( geo ) {
  180. handle_mesh( geo, id );
  181. counter_models -= 1;
  182. scope.onLoadComplete();
  183. async_callback_gate();
  184. }
  185. };
  186. function create_callback_embed( id ) {
  187. return function( geo ) {
  188. result.geometries[ id ] = geo;
  189. }
  190. };
  191. function async_callback_gate() {
  192. var progress = {
  193. totalModels : total_models,
  194. totalTextures : total_textures,
  195. loadedModels : total_models - counter_models,
  196. loadedTextures : total_textures - counter_textures
  197. };
  198. scope.callbackProgress( progress, result );
  199. scope.onLoadProgress();
  200. if( counter_models == 0 && counter_textures == 0 ) {
  201. callbackFinished( result );
  202. }
  203. };
  204. var callbackTexture = function( images ) {
  205. counter_textures -= 1;
  206. async_callback_gate();
  207. scope.onLoadComplete();
  208. };
  209. // first go synchronous elements
  210. // cameras
  211. for( dc in data.cameras ) {
  212. c = data.cameras[ dc ];
  213. if ( c.type == "perspective" ) {
  214. camera = new THREE.Camera( c.fov, c.aspect, c.near, c.far );
  215. } else if ( c.type == "ortho" ) {
  216. camera = new THREE.Camera();
  217. camera.projectionMatrix = THREE.Matrix4.makeOrtho( c.left, c.right, c.top, c.bottom, c.near, c.far );
  218. }
  219. p = c.position;
  220. t = c.target;
  221. camera.position.set( p[0], p[1], p[2] );
  222. camera.target.position.set( t[0], t[1], t[2] );
  223. result.cameras[ dc ] = camera;
  224. }
  225. // lights
  226. var hex, intensity;
  227. for ( dl in data.lights ) {
  228. l = data.lights[ dl ];
  229. hex = ( l.color !== undefined ) ? l.color : 0xffffff;
  230. intensity = ( l.intensity !== undefined ) ? l.intensity : 1;
  231. if ( l.type == "directional" ) {
  232. p = l.direction;
  233. light = new THREE.DirectionalLight( hex, intensity );
  234. light.position.set( p[0], p[1], p[2] );
  235. light.position.normalize();
  236. } else if ( l.type == "point" ) {
  237. p = l.position;
  238. d = l.distance;
  239. light = new THREE.PointLight( hex, intensity, d );
  240. light.position.set( p[0], p[1], p[2] );
  241. } else if ( l.type == "ambient" ) {
  242. light = new THREE.AmbientLight( hex );
  243. }
  244. result.scene.addLight( light );
  245. result.lights[ dl ] = light;
  246. }
  247. // fogs
  248. for( df in data.fogs ) {
  249. f = data.fogs[ df ];
  250. if ( f.type == "linear" ) {
  251. fog = new THREE.Fog( 0x000000, f.near, f.far );
  252. } else if ( f.type == "exp2" ) {
  253. fog = new THREE.FogExp2( 0x000000, f.density );
  254. }
  255. c = f.color;
  256. fog.color.setRGB( c[0], c[1], c[2] );
  257. result.fogs[ df ] = fog;
  258. }
  259. // defaults
  260. if ( result.cameras && data.defaults.camera ) {
  261. result.currentCamera = result.cameras[ data.defaults.camera ];
  262. }
  263. if ( result.fogs && data.defaults.fog ) {
  264. result.scene.fog = result.fogs[ data.defaults.fog ];
  265. }
  266. c = data.defaults.bgcolor;
  267. result.bgColor = new THREE.Color();
  268. result.bgColor.setRGB( c[0], c[1], c[2] );
  269. result.bgColorAlpha = data.defaults.bgalpha;
  270. // now come potentially asynchronous elements
  271. // geometries
  272. // count how many models will be loaded asynchronously
  273. for( dg in data.geometries ) {
  274. g = data.geometries[ dg ];
  275. if ( g.type == "bin_mesh" || g.type == "ascii_mesh" ) {
  276. counter_models += 1;
  277. scope.onLoadStart();
  278. }
  279. }
  280. total_models = counter_models;
  281. for ( dg in data.geometries ) {
  282. g = data.geometries[ dg ];
  283. if ( g.type == "cube" ) {
  284. geometry = new THREE.CubeGeometry( g.width, g.height, g.depth, g.segmentsWidth, g.segmentsHeight, g.segmentsDepth, null, g.flipped, g.sides );
  285. result.geometries[ dg ] = geometry;
  286. } else if ( g.type == "plane" ) {
  287. geometry = new THREE.PlaneGeometry( g.width, g.height, g.segmentsWidth, g.segmentsHeight );
  288. result.geometries[ dg ] = geometry;
  289. } else if ( g.type == "sphere" ) {
  290. geometry = new THREE.SphereGeometry( g.radius, g.segmentsWidth, g.segmentsHeight );
  291. result.geometries[ dg ] = geometry;
  292. } else if ( g.type == "cylinder" ) {
  293. geometry = new THREE.CylinderGeometry( g.numSegs, g.topRad, g.botRad, g.height, g.topOffset, g.botOffset );
  294. result.geometries[ dg ] = geometry;
  295. } else if ( g.type == "torus" ) {
  296. geometry = new THREE.TorusGeometry( g.radius, g.tube, g.segmentsR, g.segmentsT );
  297. result.geometries[ dg ] = geometry;
  298. } else if ( g.type == "icosahedron" ) {
  299. geometry = new THREE.IcosahedronGeometry( g.subdivisions );
  300. result.geometries[ dg ] = geometry;
  301. } else if ( g.type == "bin_mesh" ) {
  302. binLoader.load( { model: get_url( g.url, data.urlBaseType ),
  303. callback: create_callback( dg )
  304. } );
  305. } else if ( g.type == "ascii_mesh" ) {
  306. jsonLoader.load( { model: get_url( g.url, data.urlBaseType ),
  307. callback: create_callback( dg )
  308. } );
  309. } else if ( g.type == "embedded_mesh" ) {
  310. var modelJson = data.embeds[ g.id ],
  311. texture_path = "";
  312. if ( modelJson ) {
  313. jsonLoader.createModel( modelJson, create_callback_embed( dg ), texture_path );
  314. }
  315. }
  316. }
  317. // textures
  318. // count how many textures will be loaded asynchronously
  319. for( dt in data.textures ) {
  320. tt = data.textures[ dt ];
  321. if( tt.url instanceof Array ) {
  322. counter_textures += tt.url.length;
  323. for( var n = 0; n < tt.url.length; n ++ ) {
  324. scope.onLoadStart();
  325. }
  326. } else {
  327. counter_textures += 1;
  328. scope.onLoadStart();
  329. }
  330. }
  331. total_textures = counter_textures;
  332. for( dt in data.textures ) {
  333. tt = data.textures[ dt ];
  334. if ( tt.mapping != undefined && THREE[ tt.mapping ] != undefined ) {
  335. tt.mapping = new THREE[ tt.mapping ]();
  336. }
  337. if( tt.url instanceof Array ) {
  338. var url_array = [];
  339. for( var i = 0; i < tt.url.length; i ++ ) {
  340. url_array[ i ] = get_url( tt.url[ i ], data.urlBaseType );
  341. }
  342. texture = THREE.ImageUtils.loadTextureCube( url_array, tt.mapping, callbackTexture );
  343. } else {
  344. texture = THREE.ImageUtils.loadTexture( get_url( tt.url, data.urlBaseType ), tt.mapping, callbackTexture );
  345. if ( THREE[ tt.minFilter ] != undefined )
  346. texture.minFilter = THREE[ tt.minFilter ];
  347. if ( THREE[ tt.magFilter ] != undefined )
  348. texture.magFilter = THREE[ tt.magFilter ];
  349. if ( tt.repeat ) {
  350. texture.repeat.set( tt.repeat[ 0 ], tt.repeat[ 1 ] );
  351. if ( tt.repeat[ 0 ] != 1 ) texture.wrapS = THREE.RepeatWrapping;
  352. if ( tt.repeat[ 1 ] != 1 ) texture.wrapT = THREE.RepeatWrapping;
  353. }
  354. if ( tt.offset ) {
  355. texture.offset.set( tt.offset[ 0 ], tt.offset[ 1 ] );
  356. }
  357. // handle wrap after repeat so that default repeat can be overriden
  358. if ( tt.wrap ) {
  359. var wrapMap = {
  360. "repeat" : THREE.RepeatWrapping,
  361. "mirror" : THREE.MirroredRepeatWrapping
  362. }
  363. if ( wrapMap[ tt.wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ tt.wrap[ 0 ] ];
  364. if ( wrapMap[ tt.wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ tt.wrap[ 1 ] ];
  365. }
  366. }
  367. result.textures[ dt ] = texture;
  368. }
  369. // materials
  370. for ( dm in data.materials ) {
  371. m = data.materials[ dm ];
  372. for ( pp in m.parameters ) {
  373. if ( pp == "envMap" || pp == "map" || pp == "lightMap" ) {
  374. m.parameters[ pp ] = result.textures[ m.parameters[ pp ] ];
  375. } else if ( pp == "shading" ) {
  376. m.parameters[ pp ] = ( m.parameters[ pp ] == "flat" ) ? THREE.FlatShading : THREE.SmoothShading;
  377. } else if ( pp == "blending" ) {
  378. m.parameters[ pp ] = THREE[ m.parameters[ pp ] ] ? THREE[ m.parameters[ pp ] ] : THREE.NormalBlending;
  379. } else if ( pp == "combine" ) {
  380. m.parameters[ pp ] = ( m.parameters[ pp ] == "MixOperation" ) ? THREE.MixOperation : THREE.MultiplyOperation;
  381. } else if ( pp == "vertexColors" ) {
  382. if ( m.parameters[ pp ] == "face" ) {
  383. m.parameters[ pp ] = THREE.FaceColors;
  384. // default to vertex colors if "vertexColors" is anything else face colors or 0 / null / false
  385. } else if ( m.parameters[ pp ] ) {
  386. m.parameters[ pp ] = THREE.VertexColors;
  387. }
  388. }
  389. }
  390. if ( m.parameters.opacity !== undefined && m.parameters.opacity < 1.0 ) {
  391. m.parameters.transparent = true;
  392. }
  393. if ( m.parameters.normalMap ) {
  394. var shader = THREE.ShaderUtils.lib[ "normal" ];
  395. var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
  396. var diffuse = m.parameters.color;
  397. var specular = m.parameters.specular;
  398. var ambient = m.parameters.ambient;
  399. var shininess = m.parameters.shininess;
  400. uniforms[ "tNormal" ].texture = result.textures[ m.parameters.normalMap ];
  401. if ( m.parameters.normalMapFactor ) {
  402. uniforms[ "uNormalScale" ].value = m.parameters.normalMapFactor;
  403. }
  404. if ( m.parameters.map ) {
  405. uniforms[ "tDiffuse" ].texture = m.parameters.map;
  406. uniforms[ "enableDiffuse" ].value = true;
  407. }
  408. uniforms[ "enableAO" ].value = false;
  409. uniforms[ "enableSpecular" ].value = false;
  410. uniforms[ "uDiffuseColor" ].value.setHex( diffuse );
  411. uniforms[ "uSpecularColor" ].value.setHex( specular );
  412. uniforms[ "uAmbientColor" ].value.setHex( ambient );
  413. uniforms[ "uShininess" ].value = shininess;
  414. if ( m.parameters.opacity ) {
  415. uniforms[ "uOpacity" ].value = m.parameters.opacity;
  416. }
  417. var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true };
  418. material = new THREE.MeshShaderMaterial( parameters );
  419. } else {
  420. material = new THREE[ m.type ]( m.parameters );
  421. }
  422. result.materials[ dm ] = material;
  423. }
  424. // objects ( synchronous init of procedural primitives )
  425. handle_objects();
  426. // synchronous callback
  427. scope.callbackSync( result );
  428. };
  429. }
  430. };