SceneLoader.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  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. this.geometryHandlerMap = {};
  11. this.addGeometryHandler( "ascii", THREE.JSONLoader );
  12. this.addGeometryHandler( "binary", THREE.BinaryLoader );
  13. };
  14. THREE.SceneLoader.prototype.constructor = THREE.SceneLoader;
  15. THREE.SceneLoader.prototype.load = function ( url, callbackFinished ) {
  16. var scope = this;
  17. var xhr = new XMLHttpRequest();
  18. xhr.onreadystatechange = function () {
  19. if ( xhr.readyState === 4 ) {
  20. if ( xhr.status === 200 || xhr.status === 0 ) {
  21. var json = JSON.parse( xhr.responseText );
  22. scope.parse( json, callbackFinished, url );
  23. } else {
  24. console.error( "THREE.SceneLoader: Couldn't load [" + url + "] [" + xhr.status + "]" );
  25. }
  26. }
  27. };
  28. xhr.open( "GET", url, true );
  29. xhr.send( null );
  30. };
  31. THREE.SceneLoader.prototype.addGeometryHandler = function ( typeID, loaderClass ) {
  32. this.geometryHandlerMap[ typeID ] = { "loaderClass": loaderClass };
  33. };
  34. THREE.SceneLoader.prototype.parse = function ( json, callbackFinished, url ) {
  35. var scope = this;
  36. var urlBase = THREE.Loader.prototype.extractUrlBase( url );
  37. var dg, dm, dl, dc, df, dt,
  38. g, m, l, d, p, r, q, s, c, t, f, tt, pp, u,
  39. geometry, material, camera, fog,
  40. texture, images,
  41. light,
  42. counter_models, counter_textures,
  43. total_models, total_textures,
  44. result;
  45. var data = json;
  46. // async geometry loaders
  47. for ( var typeID in this.geometryHandlerMap ) {
  48. var loaderClass = this.geometryHandlerMap[ typeID ][ "loaderClass" ];
  49. this.geometryHandlerMap[ typeID ][ "loaderObject" ] = new loaderClass();
  50. }
  51. counter_models = 0;
  52. counter_textures = 0;
  53. result = {
  54. scene: new THREE.Scene(),
  55. geometries: {},
  56. materials: {},
  57. textures: {},
  58. objects: {},
  59. cameras: {},
  60. lights: {},
  61. fogs: {},
  62. empties: {}
  63. };
  64. if ( data.transform ) {
  65. var position = data.transform.position,
  66. rotation = data.transform.rotation,
  67. scale = data.transform.scale;
  68. if ( position )
  69. result.scene.position.set( position[ 0 ], position[ 1 ], position [ 2 ] );
  70. if ( rotation )
  71. result.scene.rotation.set( rotation[ 0 ], rotation[ 1 ], rotation [ 2 ] );
  72. if ( scale )
  73. result.scene.scale.set( scale[ 0 ], scale[ 1 ], scale [ 2 ] );
  74. if ( position || rotation || scale ) {
  75. result.scene.updateMatrix();
  76. result.scene.updateMatrixWorld();
  77. }
  78. }
  79. function get_url( source_url, url_type ) {
  80. if ( url_type == "relativeToHTML" ) {
  81. return source_url;
  82. } else {
  83. return urlBase + "/" + source_url;
  84. }
  85. };
  86. // toplevel loader function, delegates to handle_children
  87. function handle_objects() {
  88. handle_children( result.scene, data.objects );
  89. }
  90. // handle all the children from the loaded json and attach them to given parent
  91. function handle_children( parent, children ) {
  92. for ( var dd in children ) {
  93. // check by id if child has already been handled,
  94. // if not, create new object
  95. if ( result.objects[ dd ] === undefined ) {
  96. var o = children[ dd ];
  97. var object = null;
  98. if ( o.geometry !== undefined ) {
  99. geometry = result.geometries[ o.geometry ];
  100. // geometry already loaded
  101. if ( geometry ) {
  102. var hasNormals = false;
  103. // not anymore support for multiple materials
  104. // shouldn't really be array
  105. material = result.materials[ o.materials[ 0 ] ];
  106. hasNormals = material instanceof THREE.ShaderMaterial;
  107. if ( hasNormals ) {
  108. geometry.computeTangents();
  109. }
  110. p = o.position;
  111. r = o.rotation;
  112. q = o.quaternion;
  113. s = o.scale;
  114. m = o.matrix;
  115. // turn off quaternions, for the moment
  116. q = 0;
  117. if ( o.materials.length === 0 ) {
  118. material = new THREE.MeshFaceMaterial();
  119. }
  120. // dirty hack to handle meshes with multiple materials
  121. // just use face materials defined in model
  122. if ( o.materials.length > 1 ) {
  123. material = new THREE.MeshFaceMaterial();
  124. }
  125. if ( o.morph ) {
  126. object = new THREE.MorphAnimMesh( geometry, material );
  127. if ( o.duration !== undefined ) {
  128. object.duration = o.duration;
  129. }
  130. if ( o.time !== undefined ) {
  131. object.time = o.time;
  132. }
  133. if ( o.mirroredLoop !== undefined ) {
  134. object.mirroredLoop = o.mirroredLoop;
  135. }
  136. if ( material.morphNormals ) {
  137. geometry.computeMorphNormals();
  138. }
  139. } else {
  140. object = new THREE.Mesh( geometry, material );
  141. }
  142. object.name = dd;
  143. if ( m ) {
  144. object.matrixAutoUpdate = false;
  145. object.matrix.set(
  146. m[0], m[1], m[2], m[3],
  147. m[4], m[5], m[6], m[7],
  148. m[8], m[9], m[10], m[11],
  149. m[12], m[13], m[14], m[15]
  150. );
  151. } else {
  152. object.position.set( p[0], p[1], p[2] );
  153. if ( q ) {
  154. object.quaternion.set( q[0], q[1], q[2], q[3] );
  155. object.useQuaternion = true;
  156. } else {
  157. object.rotation.set( r[0], r[1], r[2] );
  158. }
  159. object.scale.set( s[0], s[1], s[2] );
  160. }
  161. object.visible = o.visible;
  162. object.castShadow = o.castShadow;
  163. object.receiveShadow = o.receiveShadow;
  164. parent.add( object );
  165. result.objects[ dd ] = object;
  166. }
  167. // pure Object3D
  168. } else {
  169. p = o.position;
  170. r = o.rotation;
  171. q = o.quaternion;
  172. s = o.scale;
  173. // turn off quaternions, for the moment
  174. q = 0;
  175. object = new THREE.Object3D();
  176. object.name = dd;
  177. object.position.set( p[0], p[1], p[2] );
  178. if ( q ) {
  179. object.quaternion.set( q[0], q[1], q[2], q[3] );
  180. object.useQuaternion = true;
  181. } else {
  182. object.rotation.set( r[0], r[1], r[2] );
  183. }
  184. object.scale.set( s[0], s[1], s[2] );
  185. object.visible = ( o.visible !== undefined ) ? o.visible : false;
  186. parent.add( object );
  187. result.objects[ dd ] = object;
  188. result.empties[ dd ] = object;
  189. }
  190. if ( object ) {
  191. if ( o.properties !== undefined ) {
  192. for ( var key in o.properties ) {
  193. var value = o.properties[ key ];
  194. object.properties[ key ] = value;
  195. }
  196. }
  197. if ( o.children !== undefined ) {
  198. handle_children( object, o.children );
  199. }
  200. }
  201. }
  202. }
  203. };
  204. function handle_mesh( geo, id ) {
  205. result.geometries[ id ] = geo;
  206. handle_objects();
  207. };
  208. function create_callback( id ) {
  209. return function( geo ) {
  210. handle_mesh( geo, id );
  211. counter_models -= 1;
  212. scope.onLoadComplete();
  213. async_callback_gate();
  214. }
  215. };
  216. function create_callback_embed( id ) {
  217. return function( geo ) {
  218. result.geometries[ id ] = geo;
  219. }
  220. };
  221. function async_callback_gate() {
  222. var progress = {
  223. totalModels : total_models,
  224. totalTextures : total_textures,
  225. loadedModels : total_models - counter_models,
  226. loadedTextures : total_textures - counter_textures
  227. };
  228. scope.callbackProgress( progress, result );
  229. scope.onLoadProgress();
  230. if ( counter_models === 0 && counter_textures === 0 ) {
  231. callbackFinished( result );
  232. }
  233. };
  234. var callbackTexture = function ( count ) {
  235. counter_textures -= count;
  236. async_callback_gate();
  237. scope.onLoadComplete();
  238. };
  239. // must use this instead of just directly calling callbackTexture
  240. // because of closure in the calling context loop
  241. var generateTextureCallback = function ( count ) {
  242. return function() {
  243. callbackTexture( count );
  244. };
  245. };
  246. // first go synchronous elements
  247. // cameras
  248. for( dc in data.cameras ) {
  249. c = data.cameras[ dc ];
  250. if ( c.type === "perspective" ) {
  251. camera = new THREE.PerspectiveCamera( c.fov, c.aspect, c.near, c.far );
  252. } else if ( c.type === "ortho" ) {
  253. camera = new THREE.OrthographicCamera( c.left, c.right, c.top, c.bottom, c.near, c.far );
  254. }
  255. p = c.position;
  256. t = c.target;
  257. u = c.up;
  258. camera.position.set( p[0], p[1], p[2] );
  259. camera.target = new THREE.Vector3( t[0], t[1], t[2] );
  260. if ( u ) camera.up.set( u[0], u[1], u[2] );
  261. result.cameras[ dc ] = camera;
  262. }
  263. // lights
  264. var hex, intensity;
  265. for ( dl in data.lights ) {
  266. l = data.lights[ dl ];
  267. hex = ( l.color !== undefined ) ? l.color : 0xffffff;
  268. intensity = ( l.intensity !== undefined ) ? l.intensity : 1;
  269. if ( l.type === "directional" ) {
  270. p = l.direction;
  271. light = new THREE.DirectionalLight( hex, intensity );
  272. light.position.set( p[0], p[1], p[2] );
  273. light.position.normalize();
  274. } else if ( l.type === "point" ) {
  275. p = l.position;
  276. d = l.distance;
  277. light = new THREE.PointLight( hex, intensity, d );
  278. light.position.set( p[0], p[1], p[2] );
  279. } else if ( l.type === "ambient" ) {
  280. light = new THREE.AmbientLight( hex );
  281. }
  282. result.scene.add( light );
  283. result.lights[ dl ] = light;
  284. }
  285. // fogs
  286. for( df in data.fogs ) {
  287. f = data.fogs[ df ];
  288. if ( f.type === "linear" ) {
  289. fog = new THREE.Fog( 0x000000, f.near, f.far );
  290. } else if ( f.type === "exp2" ) {
  291. fog = new THREE.FogExp2( 0x000000, f.density );
  292. }
  293. c = f.color;
  294. fog.color.setRGB( c[0], c[1], c[2] );
  295. result.fogs[ df ] = fog;
  296. }
  297. // defaults
  298. if ( result.cameras && data.defaults.camera ) {
  299. result.currentCamera = result.cameras[ data.defaults.camera ];
  300. }
  301. if ( result.fogs && data.defaults.fog ) {
  302. result.scene.fog = result.fogs[ data.defaults.fog ];
  303. }
  304. c = data.defaults.bgcolor;
  305. result.bgColor = new THREE.Color();
  306. result.bgColor.setRGB( c[0], c[1], c[2] );
  307. result.bgColorAlpha = data.defaults.bgalpha;
  308. // now come potentially asynchronous elements
  309. // geometries
  310. // count how many models will be loaded asynchronously
  311. for( dg in data.geometries ) {
  312. g = data.geometries[ dg ];
  313. if ( g.type in this.geometryHandlerMap ) {
  314. counter_models += 1;
  315. scope.onLoadStart();
  316. }
  317. }
  318. total_models = counter_models;
  319. for ( dg in data.geometries ) {
  320. g = data.geometries[ dg ];
  321. if ( g.type === "cube" ) {
  322. geometry = new THREE.CubeGeometry( g.width, g.height, g.depth, g.segmentsWidth, g.segmentsHeight, g.segmentsDepth, null, g.flipped, g.sides );
  323. result.geometries[ dg ] = geometry;
  324. } else if ( g.type === "plane" ) {
  325. geometry = new THREE.PlaneGeometry( g.width, g.height, g.segmentsWidth, g.segmentsHeight );
  326. result.geometries[ dg ] = geometry;
  327. } else if ( g.type === "sphere" ) {
  328. geometry = new THREE.SphereGeometry( g.radius, g.segmentsWidth, g.segmentsHeight );
  329. result.geometries[ dg ] = geometry;
  330. } else if ( g.type === "cylinder" ) {
  331. geometry = new THREE.CylinderGeometry( g.topRad, g.botRad, g.height, g.radSegs, g.heightSegs );
  332. result.geometries[ dg ] = geometry;
  333. } else if ( g.type === "torus" ) {
  334. geometry = new THREE.TorusGeometry( g.radius, g.tube, g.segmentsR, g.segmentsT );
  335. result.geometries[ dg ] = geometry;
  336. } else if ( g.type === "icosahedron" ) {
  337. geometry = new THREE.IcosahedronGeometry( g.radius, g.subdivisions );
  338. result.geometries[ dg ] = geometry;
  339. } else if ( g.type in this.geometryHandlerMap ) {
  340. var loaderParameters = {};
  341. for ( var parType in g ) {
  342. if ( parType !== "type" && parType !== "url" ) {
  343. loaderParameters[ parType ] = g[ parType ];
  344. }
  345. }
  346. var loader = this.geometryHandlerMap[ g.type ][ "loaderObject" ];
  347. loader.load( get_url( g.url, data.urlBaseType ), create_callback( dg ), loaderParameters );
  348. } else if ( g.type === "embedded" ) {
  349. var modelJson = data.embeds[ g.id ],
  350. texture_path = "";
  351. // pass metadata along to jsonLoader so it knows the format version
  352. modelJson.metadata = data.metadata;
  353. if ( modelJson ) {
  354. var jsonLoader = this.geometryHandlerMap[ "ascii" ][ "loaderObject" ];
  355. jsonLoader.createModel( modelJson, create_callback_embed( dg ), texture_path );
  356. }
  357. }
  358. }
  359. // textures
  360. // count how many textures will be loaded asynchronously
  361. for( dt in data.textures ) {
  362. tt = data.textures[ dt ];
  363. if( tt.url instanceof Array ) {
  364. counter_textures += tt.url.length;
  365. for( var n = 0; n < tt.url.length; n ++ ) {
  366. scope.onLoadStart();
  367. }
  368. } else {
  369. counter_textures += 1;
  370. scope.onLoadStart();
  371. }
  372. }
  373. total_textures = counter_textures;
  374. for( dt in data.textures ) {
  375. tt = data.textures[ dt ];
  376. if ( tt.mapping !== undefined && THREE[ tt.mapping ] !== undefined ) {
  377. tt.mapping = new THREE[ tt.mapping ]();
  378. }
  379. if( tt.url instanceof Array ) {
  380. var count = tt.url.length;
  381. var url_array = [];
  382. for( var i = 0; i < count; i ++ ) {
  383. url_array[ i ] = get_url( tt.url[ i ], data.urlBaseType );
  384. }
  385. texture = THREE.ImageUtils.loadTextureCube( url_array, tt.mapping, generateTextureCallback( count ) );
  386. } else {
  387. var isCompressed = tt.url.toLowerCase().endsWith( ".dds" );
  388. var fullUrl = get_url( tt.url, data.urlBaseType );
  389. var textureCallback = generateTextureCallback( 1 );
  390. if ( isCompressed ) {
  391. texture = THREE.ImageUtils.loadCompressedTexture( fullUrl, tt.mapping, textureCallback );
  392. } else {
  393. texture = THREE.ImageUtils.loadTexture( fullUrl, tt.mapping, textureCallback );
  394. }
  395. if ( THREE[ tt.minFilter ] !== undefined )
  396. texture.minFilter = THREE[ tt.minFilter ];
  397. if ( THREE[ tt.magFilter ] !== undefined )
  398. texture.magFilter = THREE[ tt.magFilter ];
  399. if ( tt.anisotropy ) texture.anisotropy = tt.anisotropy;
  400. if ( tt.repeat ) {
  401. texture.repeat.set( tt.repeat[ 0 ], tt.repeat[ 1 ] );
  402. if ( tt.repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping;
  403. if ( tt.repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping;
  404. }
  405. if ( tt.offset ) {
  406. texture.offset.set( tt.offset[ 0 ], tt.offset[ 1 ] );
  407. }
  408. // handle wrap after repeat so that default repeat can be overriden
  409. if ( tt.wrap ) {
  410. var wrapMap = {
  411. "repeat" : THREE.RepeatWrapping,
  412. "mirror" : THREE.MirroredRepeatWrapping
  413. }
  414. if ( wrapMap[ tt.wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ tt.wrap[ 0 ] ];
  415. if ( wrapMap[ tt.wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ tt.wrap[ 1 ] ];
  416. }
  417. }
  418. result.textures[ dt ] = texture;
  419. }
  420. // materials
  421. for ( dm in data.materials ) {
  422. m = data.materials[ dm ];
  423. for ( pp in m.parameters ) {
  424. if ( pp === "envMap" || pp === "map" || pp === "lightMap" || pp === "bumpMap" ) {
  425. m.parameters[ pp ] = result.textures[ m.parameters[ pp ] ];
  426. } else if ( pp === "shading" ) {
  427. m.parameters[ pp ] = ( m.parameters[ pp ] === "flat" ) ? THREE.FlatShading : THREE.SmoothShading;
  428. } else if ( pp === "side" ) {
  429. if ( m.parameters[ pp ] == "double" ) {
  430. m.parameters[ pp ] = THREE.DoubleSide;
  431. } else if ( m.parameters[ pp ] == "back" ) {
  432. m.parameters[ pp ] = THREE.BackSide;
  433. } else {
  434. m.parameters[ pp ] = THREE.FrontSide;
  435. }
  436. } else if ( pp === "blending" ) {
  437. m.parameters[ pp ] = m.parameters[ pp ] in THREE ? THREE[ m.parameters[ pp ] ] : THREE.NormalBlending;
  438. } else if ( pp === "combine" ) {
  439. m.parameters[ pp ] = ( m.parameters[ pp ] == "MixOperation" ) ? THREE.MixOperation : THREE.MultiplyOperation;
  440. } else if ( pp === "vertexColors" ) {
  441. if ( m.parameters[ pp ] == "face" ) {
  442. m.parameters[ pp ] = THREE.FaceColors;
  443. // default to vertex colors if "vertexColors" is anything else face colors or 0 / null / false
  444. } else if ( m.parameters[ pp ] ) {
  445. m.parameters[ pp ] = THREE.VertexColors;
  446. }
  447. } else if ( pp === "wrapRGB" ) {
  448. var v3 = m.parameters[ pp ];
  449. m.parameters[ pp ] = new THREE.Vector3( v3[ 0 ], v3[ 1 ], v3[ 2 ] );
  450. }
  451. }
  452. if ( m.parameters.opacity !== undefined && m.parameters.opacity < 1.0 ) {
  453. m.parameters.transparent = true;
  454. }
  455. if ( m.parameters.normalMap ) {
  456. var shader = THREE.ShaderUtils.lib[ "normal" ];
  457. var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
  458. var diffuse = m.parameters.color;
  459. var specular = m.parameters.specular;
  460. var ambient = m.parameters.ambient;
  461. var shininess = m.parameters.shininess;
  462. uniforms[ "tNormal" ].value = result.textures[ m.parameters.normalMap ];
  463. if ( m.parameters.normalScale ) {
  464. uniforms[ "uNormalScale" ].value.set( m.parameters.normalScale[ 0 ], m.parameters.normalScale[ 1 ] );
  465. }
  466. if ( m.parameters.map ) {
  467. uniforms[ "tDiffuse" ].value = m.parameters.map;
  468. uniforms[ "enableDiffuse" ].value = true;
  469. }
  470. if ( m.parameters.envMap ) {
  471. uniforms[ "tCube" ].value = m.parameters.envMap;
  472. uniforms[ "enableReflection" ].value = true;
  473. uniforms[ "uReflectivity" ].value = m.parameters.reflectivity;
  474. }
  475. if ( m.parameters.lightMap ) {
  476. uniforms[ "tAO" ].value = m.parameters.lightMap;
  477. uniforms[ "enableAO" ].value = true;
  478. }
  479. if ( m.parameters.specularMap ) {
  480. uniforms[ "tSpecular" ].value = result.textures[ m.parameters.specularMap ];
  481. uniforms[ "enableSpecular" ].value = true;
  482. }
  483. if ( m.parameters.displacementMap ) {
  484. uniforms[ "tDisplacement" ].value = result.textures[ m.parameters.displacementMap ];
  485. uniforms[ "enableDisplacement" ].value = true;
  486. uniforms[ "uDisplacementBias" ].value = m.parameters.displacementBias;
  487. uniforms[ "uDisplacementScale" ].value = m.parameters.displacementScale;
  488. }
  489. uniforms[ "uDiffuseColor" ].value.setHex( diffuse );
  490. uniforms[ "uSpecularColor" ].value.setHex( specular );
  491. uniforms[ "uAmbientColor" ].value.setHex( ambient );
  492. uniforms[ "uShininess" ].value = shininess;
  493. if ( m.parameters.opacity ) {
  494. uniforms[ "uOpacity" ].value = m.parameters.opacity;
  495. }
  496. var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true };
  497. material = new THREE.ShaderMaterial( parameters );
  498. } else {
  499. material = new THREE[ m.type ]( m.parameters );
  500. }
  501. result.materials[ dm ] = material;
  502. }
  503. // objects ( synchronous init of procedural primitives )
  504. handle_objects();
  505. // synchronous callback
  506. scope.callbackSync( result );
  507. // just in case there are no async elements
  508. async_callback_gate();
  509. };
粤ICP备19079148号