ColladaLoader2.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878
  1. /**
  2. * @author mrdoob / http://mrdoob.com/
  3. */
  4. THREE.ColladaLoader = function ( manager ) {
  5. this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
  6. };
  7. THREE.ColladaLoader.prototype = {
  8. constructor: THREE.ColladaLoader,
  9. load: function ( url, onLoad, onProgress, onError ) {
  10. var scope = this;
  11. var resourceDirectory = url.split( /[\\\/]/ );
  12. resourceDirectory.pop();
  13. resourceDirectory = resourceDirectory.join( '/' ) + '/';
  14. var loader = new THREE.FileLoader( scope.manager );
  15. loader.load( url, function ( text ) {
  16. onLoad( scope.parse( text, resourceDirectory ) );
  17. }, onProgress, onError );
  18. },
  19. options: {
  20. set convertUpAxis( value ) {
  21. console.log( 'THREE.ColladaLoader.options.convertUpAxis: TODO' );
  22. }
  23. },
  24. setCrossOrigin: function ( value ) {
  25. this.crossOrigin = value;
  26. },
  27. parse: function ( text, resourceDirectory ) {
  28. function getElementsByTagName( xml, name ) {
  29. // Non recursive xml.getElementsByTagName() ...
  30. var array = [];
  31. var childNodes = xml.childNodes;
  32. for ( var i = 0, l = childNodes.length; i < l; i ++ ) {
  33. var child = childNodes[ i ];
  34. if ( child.nodeName === name ) {
  35. array.push( child );
  36. }
  37. }
  38. return array;
  39. }
  40. function parseFloats( text ) {
  41. if ( text.length === 0 ) return [];
  42. var parts = text.trim().split( /\s+/ );
  43. var array = new Array( parts.length );
  44. for ( var i = 0, l = parts.length; i < l; i ++ ) {
  45. array[ i ] = parseFloat( parts[ i ] );
  46. }
  47. return array;
  48. }
  49. function parseInts( text ) {
  50. if ( text.length === 0 ) return [];
  51. var parts = text.trim().split( /\s+/ );
  52. var array = new Array( parts.length );
  53. for ( var i = 0, l = parts.length; i < l; i ++ ) {
  54. array[ i ] = parseInt( parts[ i ] );
  55. }
  56. return array;
  57. }
  58. function parseId( text ) {
  59. return text.substring( 1 );
  60. }
  61. // asset
  62. function parseAsset( xml ) {
  63. return {
  64. unit: parseAssetUnit( getElementsByTagName( xml, 'unit' )[ 0 ] ),
  65. upAxis: parseAssetUpAxis( getElementsByTagName( xml, 'up_axis' )[ 0 ] )
  66. };
  67. }
  68. function parseAssetUnit( xml ) {
  69. return xml !== undefined ? parseFloat( xml.getAttribute( 'meter' ) ) : 1;
  70. }
  71. function parseAssetUpAxis( xml ) {
  72. return xml !== undefined ? xml.textContent : 'Y_UP';
  73. }
  74. // library
  75. function parseLibrary( xml, libraryName, nodeName, parser ) {
  76. var library = getElementsByTagName( xml, libraryName )[ 0 ];
  77. if ( library !== undefined ) {
  78. var elements = getElementsByTagName( library, nodeName );
  79. for ( var i = 0; i < elements.length; i ++ ) {
  80. parser( elements[ i ] );
  81. }
  82. }
  83. }
  84. function buildLibrary( data, builder ) {
  85. for ( var name in data ) {
  86. var object = data[ name ];
  87. object.build = builder( data[ name ] );
  88. }
  89. }
  90. // get
  91. function getBuild( data, builder ) {
  92. if ( data.build !== undefined ) return data.build;
  93. data.build = builder( data );
  94. return data.build;
  95. }
  96. // animation
  97. function parseAnimation( xml ) {
  98. var data = {
  99. sources: {},
  100. samplers: {},
  101. channels: {}
  102. };
  103. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  104. var child = xml.childNodes[ i ];
  105. if ( child.nodeType !== 1 ) continue;
  106. var id;
  107. switch ( child.nodeName ) {
  108. case 'source':
  109. id = child.getAttribute( 'id' );
  110. data.sources[ id ] = parseSource( child );
  111. break;
  112. case 'sampler':
  113. id = child.getAttribute( 'id' );
  114. data.samplers[ id ] = parseAnimationSampler( child );
  115. break;
  116. case 'channel':
  117. id = child.getAttribute( 'target' );
  118. data.channels[ id ] = parseAnimationChannel( child );
  119. break;
  120. default:
  121. console.log( child );
  122. }
  123. }
  124. library.animations[ xml.getAttribute( 'id' ) ] = data;
  125. }
  126. function parseAnimationSampler( xml ) {
  127. var data = {
  128. inputs: {},
  129. };
  130. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  131. var child = xml.childNodes[ i ];
  132. if ( child.nodeType !== 1 ) continue;
  133. switch ( child.nodeName ) {
  134. case 'input':
  135. var id = parseId( child.getAttribute( 'source' ) );
  136. var semantic = child.getAttribute( 'semantic' );
  137. data.inputs[ semantic ] = id;
  138. break;
  139. }
  140. }
  141. return data;
  142. }
  143. function parseAnimationChannel( xml ) {
  144. var data = {};
  145. var target = xml.getAttribute( 'target' );
  146. // parsing SID Addressing Syntax
  147. var parts = target.split( '/' );
  148. var id = parts.shift();
  149. var sid = parts.shift();
  150. // check selection syntax
  151. var arraySyntax = ( sid.indexOf( '(' ) !== - 1 );
  152. var memberSyntax = ( sid.indexOf( '.' ) !== - 1 );
  153. if ( memberSyntax ) {
  154. // member selection access
  155. parts = sid.split( '.' );
  156. sid = parts.shift();
  157. data.member = parts.shift();
  158. } else if ( arraySyntax ) {
  159. // array-access syntax. can be used to express fields in one-dimensional vectors or two-dimensional matrices.
  160. var indices = sid.split( '(' );
  161. sid = indices.shift();
  162. for ( var i = 0; i < indices.length; i ++ ) {
  163. indices[ i ] = parseInt( indices[ i ].replace( /\)/, '' ) );
  164. }
  165. data.indices = indices;
  166. }
  167. data.id = id;
  168. data.sid = sid;
  169. data.arraySyntax = arraySyntax;
  170. data.memberSyntax = memberSyntax;
  171. data.sampler = parseId( xml.getAttribute( 'source' ) );
  172. return data;
  173. }
  174. // controller
  175. function parseController( xml ) {
  176. var data = {
  177. skin: {}
  178. };
  179. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  180. var child = xml.childNodes[ i ];
  181. if ( child.nodeType !== 1 ) continue;
  182. switch ( child.nodeName ) {
  183. case 'skin':
  184. var id = parseId( child.getAttribute( 'source' ) );
  185. data.skin[ id ] = parseSkin( child );
  186. break;
  187. }
  188. }
  189. library.controllers[ xml.getAttribute( 'id' ) ] = data;
  190. }
  191. function parseSkin( xml ) {
  192. var data = {
  193. sources: {}
  194. }
  195. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  196. var child = xml.childNodes[ i ];
  197. if ( child.nodeType !== 1 ) continue;
  198. switch ( child.nodeName ) {
  199. case 'bind_shape_matrix':
  200. data.bindShapeMatrix = parseFloats( child.textContent );
  201. break;
  202. case 'source':
  203. var id = child.getAttribute( 'id' );
  204. data.sources[ id ] = parseSource( child );
  205. break;
  206. case 'joints':
  207. data.joints = parseJoints( child );
  208. break;
  209. case 'vertex_weights':
  210. data.vertexWeights = parseVertexWeights( child );
  211. break;
  212. }
  213. }
  214. return data;
  215. }
  216. function parseJoints( xml ) {
  217. var data = {
  218. inputs: {}
  219. }
  220. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  221. var child = xml.childNodes[ i ];
  222. if ( child.nodeType !== 1 ) continue;
  223. switch ( child.nodeName ) {
  224. case 'input':
  225. var semantic = child.getAttribute( 'semantic' );
  226. var id = parseId( child.getAttribute( 'source' ) );
  227. data.inputs[ semantic ] = id;
  228. break;
  229. }
  230. }
  231. return data;
  232. }
  233. function parseVertexWeights( xml ) {
  234. var data = {
  235. inputs: {}
  236. }
  237. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  238. var child = xml.childNodes[ i ];
  239. if ( child.nodeType !== 1 ) continue;
  240. switch ( child.nodeName ) {
  241. case 'input':
  242. var semantic = child.getAttribute( 'semantic' );
  243. var id = parseId( child.getAttribute( 'source' ) );
  244. var offset = parseInt( child.getAttribute( 'offset' ) );
  245. data.inputs[ semantic ] = { id: id, offset: offset };
  246. break;
  247. case 'vcount':
  248. data.vcount = parseInts( child.textContent );
  249. break;
  250. case 'v':
  251. data.v = parseInts( child.textContent );
  252. break;
  253. }
  254. }
  255. return data;
  256. }
  257. // image
  258. function parseImage( xml ) {
  259. var data = {
  260. init_from: getElementsByTagName( xml, 'init_from' )[ 0 ].textContent
  261. };
  262. library.images[ xml.getAttribute( 'id' ) ] = data;
  263. }
  264. function buildImage( data ) {
  265. if ( data.build !== undefined ) return data.build;
  266. return data.init_from;
  267. }
  268. function getImage( id ) {
  269. return getBuild( library.images[ id ], buildImage );
  270. }
  271. // effect
  272. function parseEffect( xml ) {
  273. var data = {};
  274. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  275. var child = xml.childNodes[ i ];
  276. if ( child.nodeType !== 1 ) continue;
  277. switch ( child.nodeName ) {
  278. case 'profile_COMMON':
  279. data.profile = parseEffectProfileCOMMON( child );
  280. break;
  281. }
  282. }
  283. library.effects[ xml.getAttribute( 'id' ) ] = data;
  284. }
  285. function parseEffectProfileCOMMON( xml ) {
  286. var data = {
  287. surfaces: {},
  288. samplers: {}
  289. };
  290. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  291. var child = xml.childNodes[ i ];
  292. if ( child.nodeType !== 1 ) continue;
  293. switch ( child.nodeName ) {
  294. case 'newparam':
  295. parseEffectNewparam( child, data );
  296. break;
  297. case 'technique':
  298. data.technique = parseEffectTechnique( child );
  299. break;
  300. }
  301. }
  302. return data;
  303. }
  304. function parseEffectNewparam( xml, data ) {
  305. var sid = xml.getAttribute( 'sid' );
  306. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  307. var child = xml.childNodes[ i ];
  308. if ( child.nodeType !== 1 ) continue;
  309. switch ( child.nodeName ) {
  310. case 'surface':
  311. data.surfaces[ sid ] = parseEffectSurface( child );
  312. break;
  313. case 'sampler2D':
  314. data.samplers[ sid ] = parseEffectSampler( child );
  315. break;
  316. }
  317. }
  318. }
  319. function parseEffectSurface( xml ) {
  320. var data = {};
  321. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  322. var child = xml.childNodes[ i ];
  323. if ( child.nodeType !== 1 ) continue;
  324. switch ( child.nodeName ) {
  325. case 'init_from':
  326. data.init_from = child.textContent;
  327. break;
  328. }
  329. }
  330. return data;
  331. }
  332. function parseEffectSampler( xml ) {
  333. var data = {};
  334. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  335. var child = xml.childNodes[ i ];
  336. if ( child.nodeType !== 1 ) continue;
  337. switch ( child.nodeName ) {
  338. case 'source':
  339. data.source = child.textContent;
  340. break;
  341. }
  342. }
  343. return data;
  344. }
  345. function parseEffectTechnique( xml ) {
  346. var data = {};
  347. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  348. var child = xml.childNodes[ i ];
  349. if ( child.nodeType !== 1 ) continue;
  350. switch ( child.nodeName ) {
  351. case 'constant':
  352. case 'lambert':
  353. case 'blinn':
  354. case 'phong':
  355. data.type = child.nodeName;
  356. data.parameters = parseEffectParameters( child );
  357. break;
  358. }
  359. }
  360. return data;
  361. }
  362. function parseEffectParameters( xml ) {
  363. var data = {};
  364. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  365. var child = xml.childNodes[ i ];
  366. if ( child.nodeType !== 1 ) continue;
  367. switch ( child.nodeName ) {
  368. case 'emission':
  369. case 'diffuse':
  370. case 'specular':
  371. case 'shininess':
  372. case 'transparent':
  373. case 'transparency':
  374. data[ child.nodeName ] = parseEffectParameter( child );
  375. break;
  376. }
  377. }
  378. return data;
  379. }
  380. function parseEffectParameter( xml ) {
  381. var data = {};
  382. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  383. var child = xml.childNodes[ i ];
  384. if ( child.nodeType !== 1 ) continue;
  385. switch ( child.nodeName ) {
  386. case 'color':
  387. data[ child.nodeName ] = parseFloats( child.textContent );
  388. break;
  389. case 'float':
  390. data[ child.nodeName ] = parseFloat( child.textContent );
  391. break;
  392. case 'texture':
  393. data[ child.nodeName ] = { id: child.getAttribute( 'texture' ), extra: parseEffectParameterTexture( child ) };
  394. break;
  395. }
  396. }
  397. return data;
  398. }
  399. function parseEffectParameterTexture( xml ) {
  400. var data = {};
  401. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  402. var child = xml.childNodes[ i ];
  403. if ( child.nodeType !== 1 ) continue;
  404. switch ( child.nodeName ) {
  405. case 'extra':
  406. data = parseEffectParameterTextureExtra( child );
  407. break;
  408. }
  409. }
  410. return data;
  411. }
  412. function parseEffectParameterTextureExtra( xml ) {
  413. var data = {};
  414. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  415. var child = xml.childNodes[ i ];
  416. if ( child.nodeType !== 1 ) continue;
  417. switch ( child.nodeName ) {
  418. case 'technique':
  419. data[ child.nodeName ] = parseEffectParameterTextureExtraTechnique( child );
  420. break;
  421. }
  422. }
  423. return data;
  424. }
  425. function parseEffectParameterTextureExtraTechnique( xml ) {
  426. var data = {};
  427. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  428. var child = xml.childNodes[ i ];
  429. if ( child.nodeType !== 1 ) continue;
  430. switch ( child.nodeName ) {
  431. case 'repeatU':
  432. case 'repeatV':
  433. case 'offsetU':
  434. case 'offsetV':
  435. data[ child.nodeName ] = parseFloat( child.textContent );
  436. break;
  437. case 'wrapU':
  438. case 'wrapV':
  439. data[ child.nodeName ] = parseInt( child.textContent );
  440. break;
  441. }
  442. }
  443. return data;
  444. }
  445. function buildEffect( data ) {
  446. return data;
  447. }
  448. function getEffect( id ) {
  449. return getBuild( library.effects[ id ], buildEffect );
  450. }
  451. // material
  452. function parseMaterial( xml ) {
  453. var data = {
  454. name: xml.getAttribute( 'name' )
  455. };
  456. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  457. var child = xml.childNodes[ i ];
  458. if ( child.nodeType !== 1 ) continue;
  459. switch ( child.nodeName ) {
  460. case 'instance_effect':
  461. data.url = parseId( child.getAttribute( 'url' ) );
  462. break;
  463. }
  464. }
  465. library.materials[ xml.getAttribute( 'id' ) ] = data;
  466. }
  467. function buildMaterial( data ) {
  468. var effect = getEffect( data.url );
  469. var technique = effect.profile.technique;
  470. var material;
  471. switch ( technique.type ) {
  472. case 'phong':
  473. case 'blinn':
  474. material = new THREE.MeshPhongMaterial();
  475. break;
  476. case 'lambert':
  477. material = new THREE.MeshLambertMaterial();
  478. break;
  479. default:
  480. material = new THREE.MeshBasicMaterial();
  481. break;
  482. }
  483. material.name = data.name;
  484. function getTexture( textureObject ) {
  485. var sampler = effect.profile.samplers[ textureObject.id ];
  486. if ( sampler !== undefined ) {
  487. var surface = effect.profile.surfaces[ sampler.source ];
  488. var texture = textureLoader.load( getImage( surface.init_from ) );
  489. var extra = textureObject.extra;
  490. if ( extra !== undefined && extra.technique !== undefined ) {
  491. var technique = extra.technique;
  492. texture.wrapS = technique.wrapU ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
  493. texture.wrapT = technique.wrapV ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
  494. texture.offset.set( technique.offsetU || 0, technique.offsetV || 0 );
  495. texture.repeat.set( technique.repeatU || 1, technique.repeatV || 1 );
  496. } else {
  497. texture.wrapS = THREE.RepeatWrapping;
  498. texture.wrapT = THREE.RepeatWrapping;
  499. }
  500. return texture;
  501. }
  502. console.error( 'THREE.ColladaLoader: Undefined sampler', textureObject.id );
  503. return null;
  504. }
  505. var parameters = technique.parameters;
  506. for ( var key in parameters ) {
  507. var parameter = parameters[ key ];
  508. switch ( key ) {
  509. case 'diffuse':
  510. if ( parameter.color ) material.color.fromArray( parameter.color );
  511. if ( parameter.texture ) material.map = getTexture( parameter.texture );
  512. break;
  513. case 'specular':
  514. if ( parameter.color && material.specular )
  515. material.specular.fromArray( parameter.color );
  516. break;
  517. case 'shininess':
  518. if ( parameter.float && material.shininess )
  519. material.shininess = parameter.float;
  520. break;
  521. case 'emission':
  522. if ( parameter.color && material.emissive )
  523. material.emissive.fromArray( parameter.color );
  524. break;
  525. case 'transparent':
  526. // if ( parameter.texture ) material.alphaMap = getTexture( parameter.texture );
  527. material.transparent = true;
  528. break;
  529. case 'transparency':
  530. if ( parameter.float !== undefined ) material.opacity = parameter.float;
  531. material.transparent = true;
  532. break;
  533. }
  534. }
  535. return material;
  536. }
  537. function getMaterial( id ) {
  538. return getBuild( library.materials[ id ], buildMaterial );
  539. }
  540. // camera
  541. function parseCamera( xml ) {
  542. var data = {
  543. name: xml.getAttribute( 'name' )
  544. };
  545. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  546. var child = xml.childNodes[ i ];
  547. if ( child.nodeType !== 1 ) continue;
  548. switch ( child.nodeName ) {
  549. case 'optics':
  550. data.optics = parseCameraOptics( child );
  551. break;
  552. }
  553. }
  554. library.cameras[ xml.getAttribute( 'id' ) ] = data;
  555. }
  556. function parseCameraOptics( xml ) {
  557. for ( var i = 0; i < xml.childNodes.length; i ++ ) {
  558. var child = xml.childNodes[ i ];
  559. switch ( child.nodeName ) {
  560. case 'technique_common':
  561. return parseCameraTechnique( child );
  562. }
  563. }
  564. return {};
  565. }
  566. function parseCameraTechnique( xml ) {
  567. var data = {};
  568. for ( var i = 0; i < xml.childNodes.length; i ++ ) {
  569. var child = xml.childNodes[ i ];
  570. switch ( child.nodeName ) {
  571. case 'perspective':
  572. case 'orthographic':
  573. data.technique = child.nodeName;
  574. data.parameters = parseCameraParameters( child );
  575. break;
  576. }
  577. }
  578. return data;
  579. }
  580. function parseCameraParameters( xml ) {
  581. var data = {};
  582. for ( var i = 0; i < xml.childNodes.length; i ++ ) {
  583. var child = xml.childNodes[ i ];
  584. switch ( child.nodeName ) {
  585. case 'xfov':
  586. case 'yfov':
  587. case 'xmag':
  588. case 'ymag':
  589. case 'znear':
  590. case 'zfar':
  591. case 'aspect_ratio':
  592. data[ child.nodeName ] = parseFloat( child.textContent );
  593. break;
  594. }
  595. }
  596. return data;
  597. }
  598. function buildCamera( data ) {
  599. var camera;
  600. switch ( data.optics.technique ) {
  601. case 'perspective':
  602. camera = new THREE.PerspectiveCamera(
  603. data.optics.parameters.yfov,
  604. data.optics.parameters.aspect_ratio,
  605. data.optics.parameters.znear,
  606. data.optics.parameters.zfar
  607. );
  608. break;
  609. case 'orthographic':
  610. var ymag = data.optics.parameters.ymag;
  611. var xmag = data.optics.parameters.xmag;
  612. var aspectRatio = data.optics.parameters.aspect_ratio;
  613. xmag = ( xmag === undefined ) ? ( ymag * aspectRatio ) : xmag;
  614. ymag = ( ymag === undefined ) ? ( xmag / aspectRatio ) : ymag;
  615. xmag *= 0.5;
  616. ymag *= 0.5;
  617. camera = new THREE.OrthographicCamera(
  618. - xmag, xmag, ymag, - ymag, // left, right, top, bottom
  619. data.optics.parameters.znear,
  620. data.optics.parameters.zfar
  621. );
  622. break;
  623. default:
  624. camera = new THREE.PerspectiveCamera();
  625. break;
  626. }
  627. camera.name = data.name;
  628. return camera;
  629. }
  630. function getCamera( id ) {
  631. return getBuild( library.cameras[ id ], buildCamera );
  632. }
  633. // light
  634. function parseLight( xml ) {
  635. var data = {};
  636. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  637. var child = xml.childNodes[ i ];
  638. if ( child.nodeType !== 1 ) continue;
  639. switch ( child.nodeName ) {
  640. case 'technique_common':
  641. data = parseLightTechnique( child );
  642. break;
  643. }
  644. }
  645. library.lights[ xml.getAttribute( 'id' ) ] = data;
  646. }
  647. function parseLightTechnique( xml ) {
  648. var data = {};
  649. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  650. var child = xml.childNodes[ i ];
  651. if ( child.nodeType !== 1 ) continue;
  652. switch ( child.nodeName ) {
  653. case 'directional':
  654. case 'point':
  655. case 'spot':
  656. case 'ambient':
  657. data.technique = child.nodeName;
  658. data.parameters = parseLightParameters( child );
  659. }
  660. }
  661. return data;
  662. }
  663. function parseLightParameters( xml ) {
  664. var data = {};
  665. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  666. var child = xml.childNodes[ i ];
  667. if ( child.nodeType !== 1 ) continue;
  668. switch ( child.nodeName ) {
  669. case 'color':
  670. var array = parseFloats( child.textContent );
  671. data.color = new THREE.Color().fromArray( array );
  672. break;
  673. case 'falloff_angle':
  674. data.falloffAngle = parseFloat( child.textContent );
  675. break;
  676. case 'quadratic_attenuation':
  677. var f = parseFloat( child.textContent );
  678. data.distance = f ? Math.sqrt( 1 / f ) : 0;
  679. break;
  680. }
  681. }
  682. return data;
  683. }
  684. function buildLight( data ) {
  685. var light;
  686. switch ( data.technique ) {
  687. case 'directional':
  688. light = new THREE.DirectionalLight();
  689. break;
  690. case 'point':
  691. light = new THREE.PointLight();
  692. break;
  693. case 'spot':
  694. light = new THREE.SpotLight();
  695. break;
  696. case 'ambient':
  697. light = new THREE.AmbientLight();
  698. break;
  699. }
  700. if ( data.parameters.color ) light.color.copy( data.parameters.color );
  701. if ( data.parameters.distance ) light.distance = data.parameters.distance;
  702. return light;
  703. }
  704. function getLight( id ) {
  705. return getBuild( library.lights[ id ], buildLight );
  706. }
  707. // geometry
  708. function parseGeometry( xml ) {
  709. var data = {
  710. name: xml.getAttribute( 'name' ),
  711. sources: {},
  712. vertices: {},
  713. primitives: []
  714. };
  715. var mesh = getElementsByTagName( xml, 'mesh' )[ 0 ];
  716. for ( var i = 0; i < mesh.childNodes.length; i ++ ) {
  717. var child = mesh.childNodes[ i ];
  718. if ( child.nodeType !== 1 ) continue;
  719. var id = child.getAttribute( 'id' );
  720. switch ( child.nodeName ) {
  721. case 'source':
  722. data.sources[ id ] = parseSource( child );
  723. break;
  724. case 'vertices':
  725. // data.sources[ id ] = data.sources[ parseId( getElementsByTagName( child, 'input' )[ 0 ].getAttribute( 'source' ) ) ];
  726. data.vertices = parseGeometryVertices( child );
  727. break;
  728. case 'polygons':
  729. console.warn( 'THREE.ColladaLoader: Unsupported primitive type: ', child.nodeName );
  730. break;
  731. case 'lines':
  732. case 'linestrips':
  733. case 'polylist':
  734. case 'triangles':
  735. data.primitives.push( parseGeometryPrimitive( child ) );
  736. break;
  737. default:
  738. console.log( child );
  739. }
  740. }
  741. library.geometries[ xml.getAttribute( 'id' ) ] = data;
  742. }
  743. function parseSource( xml ) {
  744. var data = {
  745. array: [],
  746. stride: 3
  747. };
  748. for ( var i = 0; i < xml.childNodes.length; i ++ ) {
  749. var child = xml.childNodes[ i ];
  750. if ( child.nodeType !== 1 ) continue;
  751. switch ( child.nodeName ) {
  752. case 'float_array':
  753. data.array = parseFloats( child.textContent );
  754. break;
  755. case 'technique_common':
  756. var accessor = getElementsByTagName( child, 'accessor' )[ 0 ];
  757. if ( accessor !== undefined ) {
  758. data.stride = parseInt( accessor.getAttribute( 'stride' ) );
  759. }
  760. break;
  761. default:
  762. console.log( child );
  763. }
  764. }
  765. return data;
  766. }
  767. function parseGeometryVertices( xml ) {
  768. var data = {};
  769. for ( var i = 0; i < xml.childNodes.length; i ++ ) {
  770. var child = xml.childNodes[ i ];
  771. if ( child.nodeType !== 1 ) continue;
  772. data[ child.getAttribute( 'semantic' ) ] = parseId( child.getAttribute( 'source' ) );
  773. }
  774. return data;
  775. }
  776. function parseGeometryPrimitive( xml ) {
  777. var primitive = {
  778. type: xml.nodeName,
  779. material: xml.getAttribute( 'material' ),
  780. inputs: {},
  781. stride: 0
  782. };
  783. for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
  784. var child = xml.childNodes[ i ];
  785. if ( child.nodeType !== 1 ) continue;
  786. switch ( child.nodeName ) {
  787. case 'input':
  788. var id = parseId( child.getAttribute( 'source' ) );
  789. var semantic = child.getAttribute( 'semantic' );
  790. var offset = parseInt( child.getAttribute( 'offset' ) );
  791. primitive.inputs[ semantic ] = { id: id, offset: offset };
  792. primitive.stride = Math.max( primitive.stride, offset + 1 );
  793. break;
  794. case 'vcount':
  795. primitive.vcount = parseInts( child.textContent );
  796. break;
  797. case 'p':
  798. primitive.p = parseInts( child.textContent );
  799. break;
  800. }
  801. }
  802. return primitive;
  803. }
  804. var DEFAULT_LINEMATERIAL = new THREE.LineBasicMaterial();
  805. var DEFAULT_MESHMATERIAL = new THREE.MeshPhongMaterial();
  806. function buildGeometry( data ) {
  807. var group = {};
  808. var sources = data.sources;
  809. var vertices = data.vertices;
  810. var primitives = data.primitives;
  811. if ( primitives.length === 0 ) return group;
  812. for ( var p = 0; p < primitives.length; p ++ ) {
  813. var primitive = primitives[ p ];
  814. var inputs = primitive.inputs;
  815. var geometry = new THREE.BufferGeometry();
  816. if ( data.name ) geometry.name = data.name;
  817. for ( var name in inputs ) {
  818. var input = inputs[ name ];
  819. switch ( name ) {
  820. case 'VERTEX':
  821. for ( var key in vertices ) {
  822. geometry.addAttribute( key.toLowerCase(), buildGeometryAttribute( primitive, sources[ vertices[ key ] ], input.offset ) );
  823. }
  824. break;
  825. case 'NORMAL':
  826. geometry.addAttribute( 'normal', buildGeometryAttribute( primitive, sources[ input.id ], input.offset ) );
  827. break;
  828. case 'COLOR':
  829. geometry.addAttribute( 'color', buildGeometryAttribute( primitive, sources[ input.id ], input.offset ) );
  830. break;
  831. case 'TEXCOORD':
  832. geometry.addAttribute( 'uv', buildGeometryAttribute( primitive, sources[ input.id ], input.offset ) );
  833. break;
  834. }
  835. }
  836. var object;
  837. switch ( primitive.type ) {
  838. case 'lines':
  839. object = new THREE.LineSegments( geometry, DEFAULT_LINEMATERIAL );
  840. break;
  841. case 'linestrips':
  842. object = new THREE.Line( geometry, DEFAULT_LINEMATERIAL );
  843. break;
  844. case 'triangles':
  845. case 'polylist':
  846. object = new THREE.Mesh( geometry, DEFAULT_MESHMATERIAL );
  847. break;
  848. }
  849. group[ primitive.material ] = object;
  850. }
  851. return group;
  852. }
  853. function buildGeometryAttribute( primitive, source, offset ) {
  854. var indices = primitive.p;
  855. var stride = primitive.stride;
  856. var vcount = primitive.vcount;
  857. function pushVector( i ) {
  858. var index = indices[ i + offset ] * sourceStride;
  859. var length = index + sourceStride;
  860. for ( ; index < length; index ++ ) {
  861. array.push( sourceArray[ index ] );
  862. }
  863. }
  864. var maxcount = 0;
  865. var sourceArray = source.array;
  866. var sourceStride = source.stride;
  867. var array = [];
  868. if ( primitive.vcount !== undefined ) {
  869. var index = 0;
  870. for ( var i = 0, l = vcount.length; i < l; i ++ ) {
  871. var count = vcount[ i ];
  872. if ( count === 4 ) {
  873. var a = index + stride * 0;
  874. var b = index + stride * 1;
  875. var c = index + stride * 2;
  876. var d = index + stride * 3;
  877. pushVector( a ); pushVector( b ); pushVector( d );
  878. pushVector( b ); pushVector( c ); pushVector( d );
  879. } else if ( count === 3 ) {
  880. var a = index + stride * 0;
  881. var b = index + stride * 1;
  882. var c = index + stride * 2;
  883. pushVector( a ); pushVector( b ); pushVector( c );
  884. } else {
  885. maxcount = Math.max( maxcount, count );
  886. }
  887. index += stride * count;
  888. }
  889. if ( maxcount > 0 ) {
  890. console.log( 'THREE.ColladaLoader: Geometry has faces with more than 4 vertices.' );
  891. }
  892. } else {
  893. for ( var i = 0, l = indices.length; i < l; i += stride ) {
  894. pushVector( i );
  895. }
  896. }
  897. return new THREE.Float32BufferAttribute( array, sourceStride );
  898. }
  899. function getGeometry( id ) {
  900. return getBuild( library.geometries[ id ], buildGeometry );
  901. }
  902. // nodes
  903. var matrix = new THREE.Matrix4();
  904. var vector = new THREE.Vector3();
  905. function parseNode( xml ) {
  906. var data = {
  907. name: xml.getAttribute( 'name' ),
  908. matrix: new THREE.Matrix4(),
  909. nodes: [],
  910. instanceCameras: [],
  911. instanceLights: [],
  912. instanceGeometries: [],
  913. instanceNodes: []
  914. };
  915. for ( var i = 0; i < xml.childNodes.length; i ++ ) {
  916. var child = xml.childNodes[ i ];
  917. if ( child.nodeType !== 1 ) continue;
  918. switch ( child.nodeName ) {
  919. case 'node':
  920. if ( child.hasAttribute( 'id' ) ) {
  921. data.nodes.push( child.getAttribute( 'id' ) );
  922. parseNode( child );
  923. }
  924. break;
  925. case 'instance_camera':
  926. data.instanceCameras.push( parseId( child.getAttribute( 'url' ) ) );
  927. break;
  928. case 'instance_light':
  929. data.instanceLights.push( parseId( child.getAttribute( 'url' ) ) );
  930. break;
  931. case 'instance_geometry':
  932. data.instanceGeometries.push( parseNodeInstanceGeometry( child ) );
  933. break;
  934. case 'instance_node':
  935. data.instanceNodes.push( parseId( child.getAttribute( 'url' ) ) );
  936. break;
  937. case 'matrix':
  938. var array = parseFloats( child.textContent );
  939. data.matrix.multiply( matrix.fromArray( array ).transpose() ); // .transpose() when Z_UP?
  940. break;
  941. case 'translate':
  942. var array = parseFloats( child.textContent );
  943. vector.fromArray( array );
  944. data.matrix.multiply( matrix.makeTranslation( vector.x, vector.y, vector.z ) );
  945. break;
  946. case 'rotate':
  947. var array = parseFloats( child.textContent );
  948. var angle = THREE.Math.degToRad( array[ 3 ] );
  949. data.matrix.multiply( matrix.makeRotationAxis( vector.fromArray( array ), angle ) );
  950. break;
  951. case 'scale':
  952. var array = parseFloats( child.textContent );
  953. data.matrix.scale( vector.fromArray( array ) );
  954. break;
  955. case 'extra':
  956. break;
  957. default:
  958. console.log( child );
  959. }
  960. }
  961. if ( xml.hasAttribute( 'id' ) ) {
  962. library.nodes[ xml.getAttribute( 'id' ) ] = data;
  963. }
  964. return data;
  965. }
  966. function parseNodeInstanceGeometry( xml ) {
  967. var data = {
  968. id: parseId( xml.getAttribute( 'url' ) ),
  969. materials: {}
  970. };
  971. for ( var i = 0; i < xml.childNodes.length; i ++ ) {
  972. var child = xml.childNodes[ i ];
  973. if ( child.nodeName === 'bind_material' ) {
  974. var instances = child.getElementsByTagName( 'instance_material' );
  975. for ( var j = 0; j < instances.length; j ++ ) {
  976. var instance = instances[ j ];
  977. var symbol = instance.getAttribute( 'symbol' );
  978. var target = instance.getAttribute( 'target' );
  979. data.materials[ symbol ] = parseId( target );
  980. }
  981. break;
  982. }
  983. }
  984. return data;
  985. }
  986. function buildNode( data ) {
  987. var objects = [];
  988. var matrix = data.matrix;
  989. var nodes = data.nodes;
  990. var instanceCameras = data.instanceCameras;
  991. var instanceLights = data.instanceLights;
  992. var instanceGeometries = data.instanceGeometries;
  993. var instanceNodes = data.instanceNodes;
  994. for ( var i = 0, l = nodes.length; i < l; i ++ ) {
  995. objects.push( getNode( nodes[ i ] ).clone() );
  996. }
  997. for ( var i = 0, l = instanceCameras.length; i < l; i ++ ) {
  998. objects.push( getCamera( instanceCameras[ i ] ).clone() );
  999. }
  1000. for ( var i = 0, l = instanceLights.length; i < l; i ++ ) {
  1001. objects.push( getLight( instanceLights[ i ] ).clone() );
  1002. }
  1003. for ( var i = 0, l = instanceGeometries.length; i < l; i ++ ) {
  1004. var instance = instanceGeometries[ i ];
  1005. var geometries = getGeometry( instance.id );
  1006. for ( var key in geometries ) {
  1007. var object = geometries[ key ].clone();
  1008. if ( instance.materials[ key ] !== undefined ) {
  1009. object.material = getMaterial( instance.materials[ key ] );
  1010. }
  1011. objects.push( object );
  1012. }
  1013. }
  1014. for ( var i = 0, l = instanceNodes.length; i < l; i ++ ) {
  1015. objects.push( getNode( instanceNodes[ i ] ).clone() );
  1016. }
  1017. var object;
  1018. if ( nodes.length === 0 && objects.length === 1 ) {
  1019. object = objects[ 0 ];
  1020. } else {
  1021. object = new THREE.Group();
  1022. for ( var i = 0; i < objects.length; i ++ ) {
  1023. object.add( objects[ i ] );
  1024. }
  1025. }
  1026. object.name = data.name;
  1027. object.matrix.copy( matrix );
  1028. object.matrix.decompose( object.position, object.quaternion, object.scale );
  1029. return object;
  1030. }
  1031. function getNode( id ) {
  1032. return getBuild( library.nodes[ id ], buildNode );
  1033. }
  1034. // visual scenes
  1035. function parseVisualScene( xml ) {
  1036. var data = {
  1037. name: xml.getAttribute( 'name' ),
  1038. children: []
  1039. };
  1040. var elements = getElementsByTagName( xml, 'node' );
  1041. for ( var i = 0; i < elements.length; i ++ ) {
  1042. data.children.push( parseNode( elements[ i ] ) );
  1043. }
  1044. library.visualScenes[ xml.getAttribute( 'id' ) ] = data;
  1045. }
  1046. function buildVisualScene( data ) {
  1047. var group = new THREE.Group();
  1048. group.name = data.name;
  1049. var children = data.children;
  1050. for ( var i = 0; i < children.length; i ++ ) {
  1051. group.add( buildNode( children[ i ] ) );
  1052. }
  1053. return group;
  1054. }
  1055. function getVisualScene( id ) {
  1056. return getBuild( library.visualScenes[ id ], buildVisualScene );
  1057. }
  1058. // scenes
  1059. function parseScene( xml ) {
  1060. var instance = getElementsByTagName( xml, 'instance_visual_scene' )[ 0 ];
  1061. return getVisualScene( parseId( instance.getAttribute( 'url' ) ) );
  1062. }
  1063. console.time( 'THREE.ColladaLoader' );
  1064. if ( text.length === 0 ) {
  1065. return { scene: new THREE.Scene() };
  1066. }
  1067. console.time( 'THREE.ColladaLoader: DOMParser' );
  1068. var xml = new DOMParser().parseFromString( text, 'application/xml' );
  1069. console.timeEnd( 'THREE.ColladaLoader: DOMParser' );
  1070. var collada = getElementsByTagName( xml, 'COLLADA' )[ 0 ];
  1071. // metadata
  1072. var version = collada.getAttribute( 'version' );
  1073. console.log( 'THREE.ColladaLoader: File version', version );
  1074. var asset = parseAsset( getElementsByTagName( collada, 'asset' )[ 0 ] );
  1075. var textureLoader = new THREE.TextureLoader( this.manager ).setPath( resourceDirectory );
  1076. //
  1077. var library = {
  1078. animations: {},
  1079. controllers: {},
  1080. images: {},
  1081. effects: {},
  1082. materials: {},
  1083. cameras: {},
  1084. lights: {},
  1085. geometries: {},
  1086. nodes: {},
  1087. visualScenes: {}
  1088. };
  1089. console.time( 'THREE.ColladaLoader: Parse' );
  1090. // parseLibrary( collada, 'library_animations', 'animation', parseAnimation );
  1091. // parseLibrary( collada, 'library_controllers', 'controller', parseController );
  1092. parseLibrary( collada, 'library_images', 'image', parseImage );
  1093. parseLibrary( collada, 'library_effects', 'effect', parseEffect );
  1094. parseLibrary( collada, 'library_materials', 'material', parseMaterial );
  1095. parseLibrary( collada, 'library_cameras', 'camera', parseCamera );
  1096. parseLibrary( collada, 'library_lights', 'light', parseLight );
  1097. parseLibrary( collada, 'library_geometries', 'geometry', parseGeometry );
  1098. parseLibrary( collada, 'library_nodes', 'node', parseNode );
  1099. parseLibrary( collada, 'library_visual_scenes', 'visual_scene', parseVisualScene );
  1100. console.timeEnd( 'THREE.ColladaLoader: Parse' );
  1101. console.time( 'THREE.ColladaLoader: Build' );
  1102. buildLibrary( library.images, buildImage );
  1103. buildLibrary( library.effects, buildEffect );
  1104. buildLibrary( library.materials, buildMaterial );
  1105. buildLibrary( library.cameras, buildCamera );
  1106. buildLibrary( library.lights, buildLight );
  1107. buildLibrary( library.geometries, buildGeometry );
  1108. // buildLibrary( library.nodes, buildNode );
  1109. buildLibrary( library.visualScenes, buildVisualScene );
  1110. console.timeEnd( 'THREE.ColladaLoader: Build' );
  1111. // console.log( library );
  1112. var scene = parseScene( getElementsByTagName( collada, 'scene' )[ 0 ] );
  1113. if ( asset.upAxis === 'Z_UP' ) {
  1114. scene.rotation.x = - Math.PI / 2;
  1115. }
  1116. scene.scale.multiplyScalar( asset.unit );
  1117. console.timeEnd( 'THREE.ColladaLoader' );
  1118. // console.log( scene );
  1119. return {
  1120. animations: [],
  1121. kinematics: { joints: [] },
  1122. library: library,
  1123. scene: scene
  1124. };
  1125. }
  1126. };