ColladaLoader2.js 36 KB

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