FBXLoader.js 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885
  1. /**
  2. * @author yamahigashi https://github.com/yamahigashi
  3. * @author Kyle-Larson https://github.com/Kyle-Larson
  4. *
  5. * This loader loads FBX file in *ASCII and version 7 format*.
  6. *
  7. * Support
  8. * - mesh
  9. * - skinning
  10. * - normal / uv
  11. *
  12. * Not Support
  13. * - material
  14. * - texture
  15. * - morph
  16. */
  17. ( function() {
  18. THREE.FBXLoader = function ( manager ) {
  19. THREE.Loader.call( this );
  20. this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
  21. this.textureLoader = null;
  22. this.textureBasePath = null;
  23. };
  24. THREE.FBXLoader.prototype = Object.create( THREE.Loader.prototype );
  25. THREE.FBXLoader.prototype.constructor = THREE.FBXLoader;
  26. THREE.FBXLoader.prototype.load = function ( url, onLoad, onProgress, onError ) {
  27. var scope = this;
  28. var loader = new THREE.FileLoader( scope.manager );
  29. // loader.setCrossOrigin( this.crossOrigin );
  30. loader.load( url, function ( text ) {
  31. if ( ! scope.isFbxFormatASCII( text ) ) {
  32. console.warn( 'FBXLoader: !!! FBX Binary format not supported !!!' );
  33. } else if ( ! scope.isFbxVersionSupported( text ) ) {
  34. console.warn( 'FBXLoader: !!! FBX Version below 7 not supported !!!' );
  35. } else {
  36. scope.textureBasePath = scope.extractUrlBase( url );
  37. onLoad( scope.parse( text ) );
  38. }
  39. }, onProgress, onError );
  40. };
  41. THREE.FBXLoader.prototype.setCrossOrigin = function ( value ) {
  42. this.crossOrigin = value;
  43. };
  44. THREE.FBXLoader.prototype.isFbxFormatASCII = function ( body ) {
  45. var CORRECT = [ 'K', 'a', 'y', 'd', 'a', 'r', 'a', '\\', 'F', 'B', 'X', '\\', 'B', 'i', 'n', 'a', 'r', 'y', '\\', '\\' ];
  46. var cursor = 0;
  47. var read = function ( offset ) {
  48. var result = body[ offset - 1 ];
  49. body = body.slice( cursor + offset );
  50. cursor ++;
  51. return result;
  52. };
  53. for ( var i = 0; i < CORRECT.length; ++ i ) {
  54. var num = read( 1 );
  55. if ( num == CORRECT[ i ] ) {
  56. return false;
  57. }
  58. }
  59. return true;
  60. };
  61. THREE.FBXLoader.prototype.isFbxVersionSupported = function ( body ) {
  62. var versionExp = /FBXVersion: (\d+)/;
  63. var match = body.match( versionExp );
  64. if ( match ) {
  65. var version = parseInt( match[ 1 ] );
  66. console.log( 'FBXLoader: FBX version ' + version );
  67. return version >= 7000;
  68. }
  69. return false;
  70. };
  71. THREE.FBXLoader.prototype.parse = function ( text ) {
  72. var scope = this;
  73. console.time( 'FBXLoader' );
  74. console.time( 'FBXLoader: TextParser' );
  75. var nodes = new FBXParser().parse( text );
  76. console.timeEnd( 'FBXLoader: TextParser' );
  77. console.time( 'FBXLoader: ObjectParser' );
  78. scope.hierarchy = ( new Bones() ).parseHierarchy( nodes );
  79. scope.weights = ( new Weights() ).parse( nodes, scope.hierarchy );
  80. scope.animations = ( new Animation() ).parse( nodes, scope.hierarchy );
  81. scope.textures = ( new Textures() ).parse( nodes, scope.hierarchy );
  82. scope.materials = ( new Materials() ).parse( nodes, scope.hierarchy );
  83. console.timeEnd( 'FBXLoader: ObjectParser' );
  84. console.time( 'FBXLoader: GeometryParser' );
  85. var geometries = this.parseGeometries( nodes );
  86. console.timeEnd( 'FBXLoader: GeometryParser' );
  87. var container = new THREE.Group();
  88. for ( var i = 0; i < geometries.length; ++ i ) {
  89. if ( geometries[ i ] === undefined ) {
  90. continue;
  91. }
  92. container.add( geometries[ i ] );
  93. //wireframe = new THREE.WireframeHelper( geometries[i], 0x00ff00 );
  94. //container.add( wireframe );
  95. //vnh = new THREE.VertexNormalsHelper( geometries[i], 0.6 );
  96. //container.add( vnh );
  97. //skh = new THREE.SkeletonHelper( geometries[i] );
  98. //container.add( skh );
  99. // container.add( new THREE.BoxHelper( geometries[i] ) );
  100. }
  101. console.timeEnd( 'FBXLoader' );
  102. return container;
  103. };
  104. THREE.FBXLoader.prototype.parseGeometries = function ( node ) {
  105. // has not geo, return []
  106. if ( ! ( 'Geometry' in node.Objects.subNodes ) ) {
  107. return [];
  108. }
  109. // has many
  110. var geoCount = 0;
  111. for ( var geo in node.Objects.subNodes.Geometry ) {
  112. if ( geo.match( /^\d+$/ ) ) {
  113. geoCount ++;
  114. }
  115. }
  116. var res = [];
  117. if ( geoCount > 0 ) {
  118. for ( geo in node.Objects.subNodes.Geometry ) {
  119. if ( node.Objects.subNodes.Geometry[ geo ].attrType === 'Mesh' ) {
  120. res.push( this.parseGeometry( node.Objects.subNodes.Geometry[ geo ], node ) );
  121. }
  122. }
  123. } else {
  124. res.push( this.parseGeometry( node.Objects.subNodes.Geometry, node ) );
  125. }
  126. return res;
  127. };
  128. THREE.FBXLoader.prototype.parseGeometry = function ( node, nodes ) {
  129. var geo = ( new Geometry() ).parse( node );
  130. geo.addBones( this.hierarchy.hierarchy );
  131. //*
  132. var geometry = new THREE.BufferGeometry();
  133. geometry.name = geo.name;
  134. geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( geo.vertices ), 3 ) );
  135. if ( geo.normals !== undefined && geo.normals.length > 0 ) {
  136. geometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( geo.normals ), 3 ) );
  137. }
  138. if ( geo.uvs !== undefined && geo.uvs.length > 0 ) {
  139. geometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( geo.uvs ), 2 ) );
  140. }
  141. if ( geo.indices !== undefined && geo.indices.length > 65535 ) {
  142. geometry.setIndex( new THREE.BufferAttribute( new Uint32Array( geo.indices ), 1 ) );
  143. } else if ( geo.indices !== undefined ) {
  144. geometry.setIndex( new THREE.BufferAttribute( new Uint16Array( geo.indices ), 1 ) );
  145. }
  146. geometry.verticesNeedUpdate = true;
  147. geometry.computeBoundingSphere();
  148. geometry.computeBoundingBox();
  149. var texture;
  150. var texs = this.textures.getById( nodes.searchConnectionParent( geo.id ) );
  151. if ( texs !== undefined && texs.length > 0 ) {
  152. if ( this.textureLoader === null ) {
  153. this.textureLoader = new THREE.TextureLoader();
  154. }
  155. texture = this.textureLoader.load( this.textureBasePath + '/' + texs[ 0 ].fileName );
  156. }
  157. var materials = [];
  158. var material;
  159. var mats = this.materials.getById( nodes.searchConnectionParent( geo.id ) );
  160. if ( mats !== undefined && mats.length > 0) {
  161. for(var i = 0; i < mats.length; ++i) {
  162. var mat_data = mats[i];
  163. var tmpMat;
  164. // TODO:
  165. // Cannot find a list of possible ShadingModel values.
  166. // If someone finds a list, please add additional cases
  167. // and map to appropriate materials.
  168. switch(mat_data.type) {
  169. case "phong":
  170. tmpMat = new THREE.MeshPhongMaterial();
  171. break;
  172. case "Lambert":
  173. tmpMat = new THREE.MeshLambertMaterial();
  174. break;
  175. default:
  176. console.warn("No implementation given for material type " + mat_data.type + " in FBXLoader.js. Defaulting to basic material")
  177. tmpMat = new THREE.MeshBasicMaterial({ color: 0x3300ff });
  178. break;
  179. }
  180. if (texture !== undefined) {
  181. mat_data.parameters.map = texture;
  182. }
  183. tmpMat.setValues(mat_data.parameters);
  184. materials.push(tmpMat);
  185. }
  186. if(materials.length === 1) {
  187. material = materials[0];
  188. } else {
  189. //Set up for multi-material
  190. material = new THREE.MultiMaterial(materials);
  191. var material_groupings = [];
  192. var last_material_group = -1;
  193. var material_index_list = toInt(node.subNodes.LayerElementMaterial.subNodes.Materials.properties.a.split( ',' ));
  194. for(var i = 0; i < geo.polyIndices.length; ++i) {
  195. if(last_material_group !== material_index_list[geo.polyIndices[i]]) {
  196. material_groupings.push({start: i * 3, count: 0, materialIndex: material_index_list[geo.polyIndices[i]]});
  197. last_material_group = material_index_list[geo.polyIndices[i]];
  198. }
  199. material_groupings[material_groupings.length - 1].count += 3;
  200. }
  201. geometry.groups = material_groupings;
  202. }
  203. } else {
  204. //No material found for this geometry, create default
  205. if (texture !== undefined) {
  206. material = new THREE.MeshBasicMaterial({ map: texture });
  207. } else {
  208. material = new THREE.MeshBasicMaterial({ color: 0x3300ff });
  209. }
  210. }
  211. geometry = new THREE.Geometry().fromBufferGeometry( geometry );
  212. geometry.bones = geo.bones;
  213. geometry.skinIndices = this.weights.skinIndices;
  214. geometry.skinWeights = this.weights.skinWeights;
  215. var mesh = null;
  216. if ( geo.bones === undefined || geo.skins === undefined || this.animations === undefined || this.animations.length === 0 ) {
  217. mesh = new THREE.Mesh( geometry, material );
  218. } else {
  219. material.skinning = true;
  220. mesh = new THREE.SkinnedMesh( geometry, material );
  221. this.addAnimation( mesh, this.weights.matrices, this.animations );
  222. }
  223. return mesh;
  224. };
  225. THREE.FBXLoader.prototype.addAnimation = function ( mesh, matrices, animations ) {
  226. var animationdata = { "name": 'animationtest', "fps": 30, "length": animations.length, "hierarchy": [] };
  227. for ( var i = 0; i < mesh.geometry.bones.length; ++ i ) {
  228. var name = mesh.geometry.bones[ i ].name;
  229. name = name.replace( /.*:/, '' );
  230. animationdata.hierarchy.push( { parent: mesh.geometry.bones[ i ].parent, name: name, keys: [] } );
  231. }
  232. var hasCurve = function ( animNode, attr ) {
  233. if ( animNode === undefined ) {
  234. return false;
  235. }
  236. var attrNode;
  237. switch ( attr ) {
  238. case 'S':
  239. if ( animNode.S === undefined ) {
  240. return false;
  241. }
  242. attrNode = animNode.S;
  243. break;
  244. case 'R':
  245. if ( animNode.R === undefined ) {
  246. return false;
  247. }
  248. attrNode = animNode.R;
  249. break;
  250. case 'T':
  251. if ( animNode.T === undefined ) {
  252. return false;
  253. }
  254. attrNode = animNode.T;
  255. break;
  256. }
  257. if ( attrNode.curves.x === undefined ) {
  258. return false;
  259. }
  260. if ( attrNode.curves.y === undefined ) {
  261. return false;
  262. }
  263. if ( attrNode.curves.z === undefined ) {
  264. return false;
  265. }
  266. return true;
  267. };
  268. var hasKeyOnFrame = function ( attrNode, frame ) {
  269. var x = isKeyExistOnFrame( attrNode.curves.x, frame );
  270. var y = isKeyExistOnFrame( attrNode.curves.y, frame );
  271. var z = isKeyExistOnFrame( attrNode.curves.z, frame );
  272. return x && y && z;
  273. };
  274. var isKeyExistOnFrame = function ( curve, frame ) {
  275. var value = curve.values[ frame ];
  276. return value !== undefined;
  277. };
  278. var genKey = function ( animNode, bone ) {
  279. // key initialize with its bone's bind pose at first
  280. var key = {};
  281. key.time = frame / animations.fps; // TODO:
  282. key.pos = bone.pos;
  283. key.rot = bone.rotq;
  284. key.scl = bone.scl;
  285. if ( animNode === undefined ) {
  286. return key;
  287. }
  288. try {
  289. if ( hasCurve( animNode, 'T' ) && hasKeyOnFrame( animNode.T, frame ) ) {
  290. var pos = new THREE.Vector3(
  291. animNode.T.curves.x.values[ frame ],
  292. animNode.T.curves.y.values[ frame ],
  293. animNode.T.curves.z.values[ frame ] );
  294. key.pos = [ pos.x, pos.y, pos.z ];
  295. } else {
  296. delete key.pos;
  297. }
  298. if ( hasCurve( animNode, 'R' ) && hasKeyOnFrame( animNode.R, frame ) ) {
  299. var rx = degToRad( animNode.R.curves.x.values[ frame ] );
  300. var ry = degToRad( animNode.R.curves.y.values[ frame ] );
  301. var rz = degToRad( animNode.R.curves.z.values[ frame ] );
  302. var eul = new THREE.Vector3( rx, ry, rz );
  303. var rot = quatFromVec( eul.x, eul.y, eul.z );
  304. key.rot = [ rot.x, rot.y, rot.z, rot.w ];
  305. } else {
  306. delete key.rot;
  307. }
  308. if ( hasCurve( animNode, 'S' ) && hasKeyOnFrame( animNode.S, frame ) ) {
  309. var scl = new THREE.Vector3(
  310. animNode.S.curves.x.values[ frame ],
  311. animNode.S.curves.y.values[ frame ],
  312. animNode.S.curves.z.values[ frame ] );
  313. key.scl = [ scl.x, scl.y, scl.z ];
  314. } else {
  315. delete key.scl;
  316. }
  317. } catch ( e ) {
  318. // curve is not full plotted
  319. console.log( bone );
  320. console.log( e );
  321. }
  322. return key;
  323. };
  324. var bones = mesh.geometry.bones;
  325. for ( var frame = 0; frame < animations.frames; frame ++ ) {
  326. for ( i = 0; i < bones.length; i ++ ) {
  327. var bone = bones[ i ];
  328. var animNode = animations.curves[ i ];
  329. for ( var j = 0; j < animationdata.hierarchy.length; j ++ ) {
  330. if ( animationdata.hierarchy[ j ].name === bone.name ) {
  331. animationdata.hierarchy[ j ].keys.push( genKey( animNode, bone ) );
  332. }
  333. }
  334. }
  335. }
  336. if ( mesh.geometry.animations === undefined ) {
  337. mesh.geometry.animations = [];
  338. }
  339. mesh.geometry.animations.push( THREE.AnimationClip.parseAnimation( animationdata, mesh.geometry.bones ) );
  340. };
  341. THREE.FBXLoader.prototype.loadFile = function ( url, onLoad, onProgress, onError, responseType ) {
  342. var loader = new THREE.FileLoader( this.manager );
  343. loader.setResponseType( responseType );
  344. var request = loader.load( url, function ( result ) {
  345. onLoad( result );
  346. }, onProgress, onError );
  347. return request;
  348. };
  349. THREE.FBXLoader.prototype.loadFileAsBuffer = function ( url, onload, onProgress, onError ) {
  350. this.loadFile( url, onLoad, onProgress, onError, 'arraybuffer' );
  351. };
  352. THREE.FBXLoader.prototype.loadFileAsText = function ( url, onLoad, onProgress, onError ) {
  353. this.loadFile( url, onLoad, onProgress, onError, 'text' );
  354. };
  355. /* ----------------------------------------------------------------- */
  356. function FBXNodes() {}
  357. FBXNodes.prototype.add = function ( key, val ) {
  358. this[ key ] = val;
  359. };
  360. FBXNodes.prototype.searchConnectionParent = function ( id ) {
  361. if ( this.__cache_search_connection_parent === undefined ) {
  362. this.__cache_search_connection_parent = [];
  363. }
  364. if ( this.__cache_search_connection_parent[ id ] !== undefined ) {
  365. return this.__cache_search_connection_parent[ id ];
  366. } else {
  367. this.__cache_search_connection_parent[ id ] = [];
  368. }
  369. var conns = this.Connections.properties.connections;
  370. var results = [];
  371. for ( var i = 0; i < conns.length; ++ i ) {
  372. if ( conns[ i ][ 0 ] == id ) {
  373. // 0 means scene root
  374. var res = conns[ i ][ 1 ] === 0 ? - 1 : conns[ i ][ 1 ];
  375. results.push( res );
  376. }
  377. }
  378. if ( results.length > 0 ) {
  379. this.__cache_search_connection_parent[ id ] = this.__cache_search_connection_parent[ id ].concat( results );
  380. return results;
  381. } else {
  382. this.__cache_search_connection_parent[ id ] = [ - 1 ];
  383. return [ - 1 ];
  384. }
  385. };
  386. FBXNodes.prototype.searchConnectionChildren = function ( id ) {
  387. if ( this.__cache_search_connection_children === undefined ) {
  388. this.__cache_search_connection_children = [];
  389. }
  390. if ( this.__cache_search_connection_children[ id ] !== undefined ) {
  391. return this.__cache_search_connection_children[ id ];
  392. } else {
  393. this.__cache_search_connection_children[ id ] = [];
  394. }
  395. var conns = this.Connections.properties.connections;
  396. var res = [];
  397. for ( var i = 0; i < conns.length; ++ i ) {
  398. if ( conns[ i ][ 1 ] == id ) {
  399. // 0 means scene root
  400. res.push( conns[ i ][ 0 ] === 0 ? - 1 : conns[ i ][ 0 ] );
  401. // there may more than one kid, then search to the end
  402. }
  403. }
  404. if ( res.length > 0 ) {
  405. this.__cache_search_connection_children[ id ] = this.__cache_search_connection_children[ id ].concat( res );
  406. return res;
  407. } else {
  408. this.__cache_search_connection_children[ id ] = [ - 1 ];
  409. return [ - 1 ];
  410. }
  411. };
  412. FBXNodes.prototype.searchConnectionType = function ( id, to ) {
  413. var key = id + ',' + to; // TODO: to hash
  414. if ( this.__cache_search_connection_type === undefined ) {
  415. this.__cache_search_connection_type = {};
  416. }
  417. if ( this.__cache_search_connection_type[ key ] !== undefined ) {
  418. return this.__cache_search_connection_type[ key ];
  419. } else {
  420. this.__cache_search_connection_type[ key ] = '';
  421. }
  422. var conns = this.Connections.properties.connections;
  423. for ( var i = 0; i < conns.length; ++ i ) {
  424. if ( conns[ i ][ 0 ] == id && conns[ i ][ 1 ] == to ) {
  425. // 0 means scene root
  426. this.__cache_search_connection_type[ key ] = conns[ i ][ 2 ];
  427. return conns[ i ][ 2 ];
  428. }
  429. }
  430. this.__cache_search_connection_type[ id ] = null;
  431. return null;
  432. };
  433. function FBXParser() {}
  434. FBXParser.prototype = {
  435. // constructor: FBXParser,
  436. // ------------ node stack manipulations ----------------------------------
  437. getPrevNode: function () {
  438. return this.nodeStack[ this.currentIndent - 2 ];
  439. },
  440. getCurrentNode: function () {
  441. return this.nodeStack[ this.currentIndent - 1 ];
  442. },
  443. getCurrentProp: function () {
  444. return this.currentProp;
  445. },
  446. pushStack: function ( node ) {
  447. this.nodeStack.push( node );
  448. this.currentIndent += 1;
  449. },
  450. popStack: function () {
  451. this.nodeStack.pop();
  452. this.currentIndent -= 1;
  453. },
  454. setCurrentProp: function ( val, name ) {
  455. this.currentProp = val;
  456. this.currentPropName = name;
  457. },
  458. // ----------parse ---------------------------------------------------
  459. parse: function ( text ) {
  460. this.currentIndent = 0;
  461. this.allNodes = new FBXNodes();
  462. this.nodeStack = [];
  463. this.currentProp = [];
  464. this.currentPropName = '';
  465. var split = text.split( "\n" );
  466. for ( var line in split ) {
  467. var l = split[ line ];
  468. // short cut
  469. if ( l.match( /^[\s\t]*;/ ) ) {
  470. continue;
  471. } // skip comment line
  472. if ( l.match( /^[\s\t]*$/ ) ) {
  473. continue;
  474. } // skip empty line
  475. // beginning of node
  476. var beginningOfNodeExp = new RegExp( "^\\t{" + this.currentIndent + "}(\\w+):(.*){", '' );
  477. var match = l.match( beginningOfNodeExp );
  478. if ( match ) {
  479. var nodeName = match[ 1 ].trim().replace( /^"/, '' ).replace( /"$/, "" );
  480. var nodeAttrs = match[ 2 ].split( ',' ).map( function ( element ) {
  481. return element.trim().replace( /^"/, '' ).replace( /"$/, '' );
  482. } );
  483. this.parseNodeBegin( l, nodeName, nodeAttrs || null );
  484. continue;
  485. }
  486. // node's property
  487. var propExp = new RegExp( "^\\t{" + ( this.currentIndent ) + "}(\\w+):[\\s\\t\\r\\n](.*)" );
  488. var match = l.match( propExp );
  489. if ( match ) {
  490. var propName = match[ 1 ].replace( /^"/, '' ).replace( /"$/, "" ).trim();
  491. var propValue = match[ 2 ].replace( /^"/, '' ).replace( /"$/, "" ).trim();
  492. this.parseNodeProperty( l, propName, propValue );
  493. continue;
  494. }
  495. // end of node
  496. var endOfNodeExp = new RegExp( "^\\t{" + ( this.currentIndent - 1 ) + "}}" );
  497. if ( l.match( endOfNodeExp ) ) {
  498. this.nodeEnd();
  499. continue;
  500. }
  501. // for special case,
  502. //
  503. // Vertices: *8670 {
  504. // a: 0.0356229953467846,13.9599733352661,-0.399196773.....(snip)
  505. // -0.0612030513584614,13.960485458374,-0.409748703241348,-0.10.....
  506. // 0.12490539252758,13.7450733184814,-0.454119384288788,0.09272.....
  507. // 0.0836158767342567,13.5432004928589,-0.435397416353226,0.028.....
  508. //
  509. // these case the lines must contiue with previous line
  510. if ( l.match( /^[^\s\t}]/ ) ) {
  511. this.parseNodePropertyContinued( l );
  512. }
  513. }
  514. return this.allNodes;
  515. },
  516. parseNodeBegin: function ( line, nodeName, nodeAttrs ) {
  517. // var nodeName = match[1];
  518. var node = { 'name': nodeName, properties: {}, 'subNodes': {} };
  519. var attrs = this.parseNodeAttr( nodeAttrs );
  520. var currentNode = this.getCurrentNode();
  521. // a top node
  522. if ( this.currentIndent === 0 ) {
  523. this.allNodes.add( nodeName, node );
  524. } else {
  525. // a subnode
  526. // already exists subnode, then append it
  527. if ( nodeName in currentNode.subNodes ) {
  528. var tmp = currentNode.subNodes[ nodeName ];
  529. // console.log( "duped entry found\nkey: " + nodeName + "\nvalue: " + propValue );
  530. if ( this.isFlattenNode( currentNode.subNodes[ nodeName ] ) ) {
  531. if ( attrs.id === '' ) {
  532. currentNode.subNodes[ nodeName ] = [];
  533. currentNode.subNodes[ nodeName ].push( tmp );
  534. } else {
  535. currentNode.subNodes[ nodeName ] = {};
  536. currentNode.subNodes[ nodeName ][ tmp.id ] = tmp;
  537. }
  538. }
  539. if ( attrs.id === '' ) {
  540. currentNode.subNodes[ nodeName ].push( node );
  541. } else {
  542. currentNode.subNodes[ nodeName ][ attrs.id ] = node;
  543. }
  544. } else {
  545. currentNode.subNodes[ nodeName ] = node;
  546. }
  547. }
  548. // for this ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  549. // NodeAttribute: 1001463072, "NodeAttribute::", "LimbNode" {
  550. if ( nodeAttrs ) {
  551. node.id = attrs.id;
  552. node.attrName = attrs.name;
  553. node.attrType = attrs.type;
  554. }
  555. this.pushStack( node );
  556. },
  557. parseNodeAttr: function ( attrs ) {
  558. var id = attrs[ 0 ];
  559. if ( attrs[ 0 ] !== "" ) {
  560. id = parseInt( attrs[ 0 ] );
  561. if ( isNaN( id ) ) {
  562. // PolygonVertexIndex: *16380 {
  563. id = attrs[ 0 ];
  564. }
  565. }
  566. var name;
  567. var type;
  568. if ( attrs.length > 1 ) {
  569. name = attrs[ 1 ].replace( /^(\w+)::/, '' );
  570. type = attrs[ 2 ];
  571. }
  572. return { id: id, name: name || '', type: type || '' };
  573. },
  574. parseNodeProperty: function ( line, propName, propValue ) {
  575. var currentNode = this.getCurrentNode();
  576. var parentName = currentNode.name;
  577. // special case parent node's is like "Properties70"
  578. // these chilren nodes must treat with careful
  579. if ( parentName !== undefined ) {
  580. var propMatch = parentName.match( /Properties(\d)+/ );
  581. if ( propMatch ) {
  582. this.parseNodeSpecialProperty( line, propName, propValue );
  583. return;
  584. }
  585. }
  586. // special case Connections
  587. if ( propName == 'C' ) {
  588. var connProps = propValue.split( ',' ).slice( 1 );
  589. var from = parseInt( connProps[ 0 ] );
  590. var to = parseInt( connProps[ 1 ] );
  591. var rest = propValue.split( ',' ).slice( 3 );
  592. propName = 'connections';
  593. propValue = [ from, to ];
  594. propValue = propValue.concat( rest );
  595. if ( currentNode.properties[ propName ] === undefined ) {
  596. currentNode.properties[ propName ] = [];
  597. }
  598. }
  599. // special case Connections
  600. if ( propName == 'Node' ) {
  601. var id = parseInt( propValue );
  602. currentNode.properties.id = id;
  603. currentNode.id = id;
  604. }
  605. // already exists in properties, then append this
  606. if ( propName in currentNode.properties ) {
  607. // console.log( "duped entry found\nkey: " + propName + "\nvalue: " + propValue );
  608. if ( Array.isArray( currentNode.properties[ propName ] ) ) {
  609. currentNode.properties[ propName ].push( propValue );
  610. } else {
  611. currentNode.properties[ propName ] += propValue;
  612. }
  613. } else {
  614. // console.log( propName + ": " + propValue );
  615. if ( Array.isArray( currentNode.properties[ propName ] ) ) {
  616. currentNode.properties[ propName ].push( propValue );
  617. } else {
  618. currentNode.properties[ propName ] = propValue;
  619. }
  620. }
  621. this.setCurrentProp( currentNode.properties, propName );
  622. },
  623. // TODO:
  624. parseNodePropertyContinued: function ( line ) {
  625. this.currentProp[ this.currentPropName ] += line;
  626. },
  627. parseNodeSpecialProperty: function ( line, propName, propValue ) {
  628. // split this
  629. // P: "Lcl Scaling", "Lcl Scaling", "", "A",1,1,1
  630. // into array like below
  631. // ["Lcl Scaling", "Lcl Scaling", "", "A", "1,1,1" ]
  632. var props = propValue.split( '",' ).map( function ( element ) {
  633. return element.trim().replace( /^\"/, '' ).replace( /\s/, '_' );
  634. } );
  635. var innerPropName = props[ 0 ];
  636. var innerPropType1 = props[ 1 ];
  637. var innerPropType2 = props[ 2 ];
  638. var innerPropFlag = props[ 3 ];
  639. var innerPropValue = props[ 4 ];
  640. /*
  641. if ( innerPropValue === undefined ) {
  642. innerPropValue = props[3];
  643. }
  644. */
  645. // cast value in its type
  646. switch ( innerPropType1 ) {
  647. case "int":
  648. innerPropValue = parseInt( innerPropValue );
  649. break;
  650. case "double":
  651. innerPropValue = parseFloat( innerPropValue );
  652. break;
  653. case "ColorRGB":
  654. case "Vector3D":
  655. var tmp = innerPropValue.split( ',' );
  656. innerPropValue = new THREE.Vector3( tmp[ 0 ], tmp[ 1 ], tmp[ 2 ] );
  657. break;
  658. }
  659. // CAUTION: these props must append to parent's parent
  660. this.getPrevNode().properties[ innerPropName ] = {
  661. 'type': innerPropType1,
  662. 'type2': innerPropType2,
  663. 'flag': innerPropFlag,
  664. 'value': innerPropValue
  665. };
  666. this.setCurrentProp( this.getPrevNode().properties, innerPropName );
  667. },
  668. nodeEnd: function ( line ) {
  669. this.popStack();
  670. },
  671. /* ---------------------------------------------------------------- */
  672. /* util */
  673. isFlattenNode: function ( node ) {
  674. return ( 'subNodes' in node && 'properties' in node ) ? true : false;
  675. }
  676. };
  677. function FBXAnalyzer() {}
  678. FBXAnalyzer.prototype = {
  679. };
  680. // generate skinIndices, skinWeights
  681. // @skinIndices: per vertex data, this represents the bone indexes affects that vertex
  682. // @skinWeights: per vertex data, this represents the Weight Values affects that vertex
  683. // @matrices: per `bones` data
  684. function Weights() {
  685. this.skinIndices = [];
  686. this.skinWeights = [];
  687. this.matrices = [];
  688. }
  689. Weights.prototype.parseCluster = function ( node, id, entry ) {
  690. var _p = node.searchConnectionParent( id );
  691. var _indices = toInt( entry.subNodes.Indexes.properties.a.split( ',' ) );
  692. var _weights = toFloat( entry.subNodes.Weights.properties.a.split( ',' ) );
  693. var _transform = toMat44( toFloat( entry.subNodes.Transform.properties.a.split( ',' ) ) );
  694. var _link = toMat44( toFloat( entry.subNodes.TransformLink.properties.a.split( ',' ) ) );
  695. return {
  696. 'parent': _p,
  697. 'id': parseInt( id ),
  698. 'indices': _indices,
  699. 'weights': _weights,
  700. 'transform': _transform,
  701. 'transformlink': _link,
  702. 'linkMode': entry.properties.Mode
  703. };
  704. };
  705. Weights.prototype.parse = function ( node, bones ) {
  706. this.skinIndices = [];
  707. this.skinWeights = [];
  708. this.matrices = [];
  709. var deformers = node.Objects.subNodes.Deformer;
  710. var clusters = {};
  711. for ( var id in deformers ) {
  712. if ( deformers[ id ].attrType === 'Cluster' ) {
  713. if ( ! ( 'Indexes' in deformers[ id ].subNodes ) ) {
  714. continue;
  715. }
  716. //clusters.push( this.parseCluster( node, id, deformers[id] ) );
  717. var cluster = this.parseCluster( node, id, deformers[ id ] );
  718. var boneId = node.searchConnectionChildren( cluster.id )[ 0 ];
  719. clusters[ boneId ] = cluster;
  720. }
  721. }
  722. // this clusters is per Bone data, thus we make this into per vertex data
  723. var weights = [];
  724. var hi = bones.hierarchy;
  725. for ( var b = 0; b < hi.length; ++ b ) {
  726. var bid = hi[ b ].internalId;
  727. if ( clusters[ bid ] === undefined ) {
  728. //console.log( bid );
  729. this.matrices.push( new THREE.Matrix4() );
  730. continue;
  731. }
  732. var clst = clusters[ bid ];
  733. // store transform matrix per bones
  734. this.matrices.push( clst.transform );
  735. //this.matrices.push( clst.transformlink );
  736. for ( var v = 0; v < clst.indices.length; ++ v ) {
  737. if ( weights[ clst.indices[ v ] ] === undefined ) {
  738. weights[ clst.indices[ v ] ] = {};
  739. weights[ clst.indices[ v ] ].joint = [];
  740. weights[ clst.indices[ v ] ].weight = [];
  741. }
  742. // indices
  743. var affect = node.searchConnectionChildren( clst.id );
  744. if ( affect.length > 1 ) {
  745. console.warn( "FBXLoader: node " + clst.id + " have many weight kids: " + affect );
  746. }
  747. weights[ clst.indices[ v ] ].joint.push( bones.getBoneIdfromInternalId( node, affect[ 0 ] ) );
  748. // weight value
  749. weights[ clst.indices[ v ] ].weight.push( clst.weights[ v ] );
  750. }
  751. }
  752. // normalize the skin weights
  753. // TODO - this might be a good place to choose greatest 4 weights
  754. for ( var i = 0; i < weights.length; i ++ ) {
  755. var indicies = new THREE.Vector4(
  756. weights[ i ].joint[ 0 ] ? weights[ i ].joint[ 0 ] : 0,
  757. weights[ i ].joint[ 1 ] ? weights[ i ].joint[ 1 ] : 0,
  758. weights[ i ].joint[ 2 ] ? weights[ i ].joint[ 2 ] : 0,
  759. weights[ i ].joint[ 3 ] ? weights[ i ].joint[ 3 ] : 0 );
  760. var weight = new THREE.Vector4(
  761. weights[ i ].weight[ 0 ] ? weights[ i ].weight[ 0 ] : 0,
  762. weights[ i ].weight[ 1 ] ? weights[ i ].weight[ 1 ] : 0,
  763. weights[ i ].weight[ 2 ] ? weights[ i ].weight[ 2 ] : 0,
  764. weights[ i ].weight[ 3 ] ? weights[ i ].weight[ 3 ] : 0 );
  765. this.skinIndices.push( indicies );
  766. this.skinWeights.push( weight );
  767. }
  768. //console.log( this );
  769. return this;
  770. };
  771. function Bones() {
  772. // returns bones hierarchy tree.
  773. // [
  774. // {
  775. // "parent": id,
  776. // "name": name,
  777. // "pos": pos,
  778. // "rotq": quat
  779. // },
  780. // ...
  781. // {},
  782. // ...
  783. // ]
  784. //
  785. /* sample response
  786. "bones" : [
  787. {"parent":-1, "name":"Fbx01", "pos":[-0.002, 98.739, 1.6e-05], "rotq":[0, 0, 0, 1]},
  788. {"parent":0, "name":"Fbx01_Pelvis", "pos":[0.00015963, 0, 7.33107e-08], "rotq":[0, 0, 0, 1]},
  789. {"parent":1, "name":"Fbx01_Spine", "pos":[6.577e-06, 10.216, 0.0106811], "rotq":[0, 0, 0, 1]},
  790. {"parent":2, "name":"Fbx01_R_Thigh", "pos":[14.6537, -10.216, -0.00918758], "rotq":[0, 0, 0, 1]},
  791. {"parent":3, "name":"Fbx01_R_Calf", "pos":[-3.70047, -42.9681, -7.78158], "rotq":[0, 0, 0, 1]},
  792. {"parent":4, "name":"Fbx01_R_Foot", "pos":[-2.0696, -46.0488, 9.42052], "rotq":[0, 0, 0, 1]},
  793. {"parent":5, "name":"Fbx01_R_Toe0", "pos":[-0.0234785, -9.46233, -15.3187], "rotq":[0, 0, 0, 1]},
  794. {"parent":2, "name":"Fbx01_L_Thigh", "pos":[-14.6537, -10.216, -0.00918314], "rotq":[0, 0, 0, 1]},
  795. {"parent":7, "name":"Fbx01_L_Calf", "pos":[3.70037, -42.968, -7.78155], "rotq":[0, 0, 0, 1]},
  796. {"parent":8, "name":"Fbx01_L_Foot", "pos":[2.06954, -46.0488, 9.42052], "rotq":[0, 0, 0, 1]},
  797. {"parent":9, "name":"Fbx01_L_Toe0", "pos":[0.0234566, -9.46235, -15.3187], "rotq":[0, 0, 0, 1]},
  798. {"parent":2, "name":"Fbx01_Spine1", "pos":[-2.97523e-05, 11.5892, -9.81027e-05], "rotq":[0, 0, 0, 1]},
  799. {"parent":11, "name":"Fbx01_Spine2", "pos":[-2.91292e-05, 11.4685, 8.27126e-05], "rotq":[0, 0, 0, 1]},
  800. {"parent":12, "name":"Fbx01_Spine3", "pos":[-4.48857e-05, 11.5783, 8.35108e-05], "rotq":[0, 0, 0, 1]},
  801. {"parent":13, "name":"Fbx01_Neck", "pos":[1.22987e-05, 11.5582, -0.0044775], "rotq":[0, 0, 0, 1]},
  802. {"parent":14, "name":"Fbx01_Head", "pos":[-3.50709e-05, 6.62915, -0.00523254], "rotq":[0, 0, 0, 1]},
  803. {"parent":15, "name":"Fbx01_R_Eye", "pos":[3.31681, 12.739, -10.5267], "rotq":[0, 0, 0, 1]},
  804. {"parent":15, "name":"Fbx01_L_Eye", "pos":[-3.32038, 12.7391, -10.5267], "rotq":[0, 0, 0, 1]},
  805. {"parent":15, "name":"Jaw", "pos":[-0.0017738, 7.43481, -4.08114], "rotq":[0, 0, 0, 1]},
  806. {"parent":14, "name":"Fbx01_R_Clavicle", "pos":[3.10919, 2.46577, -0.0115284], "rotq":[0, 0, 0, 1]},
  807. {"parent":19, "name":"Fbx01_R_UpperArm", "pos":[16.014, 4.57764e-05, 3.10405], "rotq":[0, 0, 0, 1]},
  808. {"parent":20, "name":"Fbx01_R_Forearm", "pos":[22.7068, -1.66322, -2.13803], "rotq":[0, 0, 0, 1]},
  809. {"parent":21, "name":"Fbx01_R_Hand", "pos":[25.5881, -0.80249, -6.37307], "rotq":[0, 0, 0, 1]},
  810. ...
  811. {"parent":27, "name":"Fbx01_R_Finger32", "pos":[2.15572, -0.548737, -0.539604], "rotq":[0, 0, 0, 1]},
  812. {"parent":22, "name":"Fbx01_R_Finger2", "pos":[9.79318, 0.132553, -2.97845], "rotq":[0, 0, 0, 1]},
  813. {"parent":29, "name":"Fbx01_R_Finger21", "pos":[2.74037, 0.0483093, -0.650531], "rotq":[0, 0, 0, 1]},
  814. {"parent":55, "name":"Fbx01_L_Finger02", "pos":[-1.65308, -1.43208, -1.82885], "rotq":[0, 0, 0, 1]}
  815. ]
  816. */
  817. this.hierarchy = [];
  818. }
  819. Bones.prototype.parseHierarchy = function ( node ) {
  820. var objects = node.Objects;
  821. var models = objects.subNodes.Model;
  822. var bones = [];
  823. for ( var id in models ) {
  824. if ( models[ id ].attrType === undefined ) {
  825. continue;
  826. }
  827. bones.push( models[ id ] );
  828. }
  829. this.hierarchy = [];
  830. for ( var i = 0; i < bones.length; ++ i ) {
  831. var bone = bones[ i ];
  832. var p = node.searchConnectionParent( bone.id )[ 0 ];
  833. var t = [ 0.0, 0.0, 0.0 ];
  834. var r = [ 0.0, 0.0, 0.0, 1.0 ];
  835. var s = [ 1.0, 1.0, 1.0 ];
  836. if ( 'Lcl_Translation' in bone.properties ) {
  837. t = toFloat( bone.properties.Lcl_Translation.value.split( ',' ) );
  838. }
  839. if ( 'Lcl_Rotation' in bone.properties ) {
  840. r = toRad( toFloat( bone.properties.Lcl_Rotation.value.split( ',' ) ) );
  841. var q = new THREE.Quaternion();
  842. q.setFromEuler( new THREE.Euler( r[ 0 ], r[ 1 ], r[ 2 ], 'ZYX' ) );
  843. r = [ q.x, q.y, q.z, q.w ];
  844. }
  845. if ( 'Lcl_Scaling' in bone.properties ) {
  846. s = toFloat( bone.properties.Lcl_Scaling.value.split( ',' ) );
  847. }
  848. // replace unsafe character
  849. var name = bone.attrName;
  850. name = name.replace( /:/, '' );
  851. name = name.replace( /_/, '' );
  852. name = name.replace( /-/, '' );
  853. this.hierarchy.push( { "parent": p, "name": name, "pos": t, "rotq": r, "scl": s, "internalId": bone.id } );
  854. }
  855. this.reindexParentId();
  856. this.restoreBindPose( node );
  857. return this;
  858. };
  859. Bones.prototype.reindexParentId = function () {
  860. for ( var h = 0; h < this.hierarchy.length; h ++ ) {
  861. for ( var ii = 0; ii < this.hierarchy.length; ++ ii ) {
  862. if ( this.hierarchy[ h ].parent == this.hierarchy[ ii ].internalId ) {
  863. this.hierarchy[ h ].parent = ii;
  864. break;
  865. }
  866. }
  867. }
  868. };
  869. Bones.prototype.restoreBindPose = function ( node ) {
  870. var bindPoseNode = node.Objects.subNodes.Pose;
  871. if ( bindPoseNode === undefined ) {
  872. return;
  873. }
  874. var poseNode = bindPoseNode.subNodes.PoseNode;
  875. var localMatrices = {}; // store local matrices, modified later( initialy world space )
  876. var worldMatrices = {}; // store world matrices
  877. for ( var i = 0; i < poseNode.length; ++ i ) {
  878. var rawMatLcl = toMat44( poseNode[ i ].subNodes.Matrix.properties.a.split( ',' ) );
  879. var rawMatWrd = toMat44( poseNode[ i ].subNodes.Matrix.properties.a.split( ',' ) );
  880. localMatrices[ poseNode[ i ].id ] = rawMatLcl;
  881. worldMatrices[ poseNode[ i ].id ] = rawMatWrd;
  882. }
  883. for ( var h = 0; h < this.hierarchy.length; ++ h ) {
  884. var bone = this.hierarchy[ h ];
  885. var inId = bone.internalId;
  886. if ( worldMatrices[ inId ] === undefined ) {
  887. // has no bind pose node, possibly be mesh
  888. // console.log( bone );
  889. continue;
  890. }
  891. var t = new THREE.Vector3( 0, 0, 0 );
  892. var r = new THREE.Quaternion();
  893. var s = new THREE.Vector3( 1, 1, 1 );
  894. var parentId;
  895. var parentNodes = node.searchConnectionParent( inId );
  896. for ( var pn = 0; pn < parentNodes.length; ++ pn ) {
  897. if ( this.isBoneNode( parentNodes[ pn ] ) ) {
  898. parentId = parentNodes[ pn ];
  899. break;
  900. }
  901. }
  902. if ( parentId !== undefined && localMatrices[ parentId ] !== undefined ) {
  903. // convert world space matrix into local space
  904. var inv = new THREE.Matrix4();
  905. inv.getInverse( worldMatrices[ parentId ] );
  906. inv.multiply( localMatrices[ inId ] );
  907. localMatrices[ inId ] = inv;
  908. } else {
  909. //console.log( bone );
  910. }
  911. localMatrices[ inId ].decompose( t, r, s );
  912. bone.pos = [ t.x, t.y, t.z ];
  913. bone.rotq = [ r.x, r.y, r.z, r.w ];
  914. bone.scl = [ s.x, s.y, s.z ];
  915. }
  916. };
  917. Bones.prototype.searchRealId = function ( internalId ) {
  918. for ( var h = 0; h < this.hierarchy.length; h ++ ) {
  919. if ( internalId == this.hierarchy[ h ].internalId ) {
  920. return h;
  921. }
  922. }
  923. // console.warn( 'FBXLoader: notfound internalId in bones: ' + internalId);
  924. return - 1;
  925. };
  926. Bones.prototype.getByInternalId = function ( internalId ) {
  927. for ( var h = 0; h < this.hierarchy.length; h ++ ) {
  928. if ( internalId == this.hierarchy[ h ].internalId ) {
  929. return this.hierarchy[ h ];
  930. }
  931. }
  932. return null;
  933. };
  934. Bones.prototype.isBoneNode = function ( id ) {
  935. for ( var i = 0; i < this.hierarchy.length; ++ i ) {
  936. if ( id === this.hierarchy[ i ].internalId ) {
  937. return true;
  938. }
  939. }
  940. return false;
  941. };
  942. Bones.prototype.getBoneIdfromInternalId = function ( node, id ) {
  943. if ( node.__cache_get_boneid_from_internalid === undefined ) {
  944. node.__cache_get_boneid_from_internalid = [];
  945. }
  946. if ( node.__cache_get_boneid_from_internalid[ id ] !== undefined ) {
  947. return node.__cache_get_boneid_from_internalid[ id ];
  948. }
  949. for ( var i = 0; i < this.hierarchy.length; ++ i ) {
  950. if ( this.hierarchy[ i ].internalId == id ) {
  951. var res = i;
  952. node.__cache_get_boneid_from_internalid[ id ] = i;
  953. return i;
  954. }
  955. }
  956. // console.warn( 'FBXLoader: bone internalId(' + id + ') not found in bone hierarchy' );
  957. return - 1;
  958. };
  959. function Geometry() {
  960. this.node = null;
  961. this.name = null;
  962. this.id = null;
  963. this.vertices = [];
  964. this.indices = [];
  965. this.normals = [];
  966. this.uvs = [];
  967. this.bones = [];
  968. this.skins = null;
  969. }
  970. Geometry.prototype.parse = function ( geoNode ) {
  971. this.node = geoNode;
  972. this.name = geoNode.attrName;
  973. this.id = geoNode.id;
  974. this.vertices = this.getVertices();
  975. if ( this.vertices === undefined ) {
  976. console.log( 'FBXLoader: Geometry.parse(): pass' + this.node.id );
  977. return;
  978. }
  979. this.indices = this.getPolygonVertexIndices();
  980. this.uvs = ( new UV() ).parse( this.node, this );
  981. this.normals = ( new Normal() ).parse( this.node, this );
  982. if ( this.getPolygonTopologyMax() > 3 ) {
  983. var indexInfo = this.convertPolyIndicesToTri(
  984. this.indices, this.getPolygonTopologyArray() );
  985. this.indices = indexInfo.res;
  986. this.polyIndices = indexInfo.polyIndices;
  987. }
  988. return this;
  989. };
  990. Geometry.prototype.getVertices = function () {
  991. if ( this.node.__cache_vertices ) {
  992. return this.node.__cache_vertices;
  993. }
  994. if ( this.node.subNodes.Vertices === undefined ) {
  995. console.warn( 'this.node: ' + this.node.attrName + "(" + this.node.id + ") does not have Vertices" );
  996. this.node.__cache_vertices = undefined;
  997. return null;
  998. }
  999. var rawTextVert = this.node.subNodes.Vertices.properties.a;
  1000. var vertices = rawTextVert.split( ',' ).map( function ( element ) {
  1001. return parseFloat( element );
  1002. } );
  1003. this.node.__cache_vertices = vertices;
  1004. return this.node.__cache_vertices;
  1005. };
  1006. Geometry.prototype.getPolygonVertexIndices = function () {
  1007. if ( this.node.__cache_indices && this.node.__cache_poly_topology_max ) {
  1008. return this.node.__cache_indices;
  1009. }
  1010. if ( this.node.subNodes === undefined ) {
  1011. console.error( 'this.node.subNodes undefined' );
  1012. console.log( this.node );
  1013. return;
  1014. }
  1015. if ( this.node.subNodes.PolygonVertexIndex === undefined ) {
  1016. console.warn( 'this.node: ' + this.node.attrName + "(" + this.node.id + ") does not have PolygonVertexIndex " );
  1017. this.node.__cache_indices = undefined;
  1018. return;
  1019. }
  1020. var rawTextIndices = this.node.subNodes.PolygonVertexIndex.properties.a;
  1021. var indices = rawTextIndices.split( ',' );
  1022. var currentTopo = 1;
  1023. var topologyN = null;
  1024. var topologyArr = [];
  1025. // The indices that make up the polygon are in order and a negative index
  1026. // means that it’s the last index of the polygon. That index needs
  1027. // to be made positive and then you have to subtract 1 from it!
  1028. for ( var i = 0; i < indices.length; ++ i ) {
  1029. var tmpI = parseInt( indices[ i ] );
  1030. // found n
  1031. if ( tmpI < 0 ) {
  1032. if ( currentTopo > topologyN ) {
  1033. topologyN = currentTopo;
  1034. }
  1035. indices[ i ] = tmpI ^ - 1;
  1036. topologyArr.push( currentTopo );
  1037. currentTopo = 1;
  1038. } else {
  1039. indices[ i ] = tmpI;
  1040. currentTopo ++;
  1041. }
  1042. }
  1043. if ( topologyN === null ) {
  1044. console.warn( "FBXLoader: topology N not found: " + this.node.attrName );
  1045. console.warn( this.node );
  1046. topologyN = 3;
  1047. }
  1048. this.node.__cache_poly_topology_max = topologyN;
  1049. this.node.__cache_poly_topology_arr = topologyArr;
  1050. this.node.__cache_indices = indices;
  1051. return this.node.__cache_indices;
  1052. };
  1053. Geometry.prototype.getPolygonTopologyMax = function () {
  1054. if ( this.node.__cache_indices && this.node.__cache_poly_topology_max ) {
  1055. return this.node.__cache_poly_topology_max;
  1056. }
  1057. this.getPolygonVertexIndices( this.node );
  1058. return this.node.__cache_poly_topology_max;
  1059. };
  1060. Geometry.prototype.getPolygonTopologyArray = function () {
  1061. if ( this.node.__cache_indices && this.node.__cache_poly_topology_max ) {
  1062. return this.node.__cache_poly_topology_arr;
  1063. }
  1064. this.getPolygonVertexIndices( this.node );
  1065. return this.node.__cache_poly_topology_arr;
  1066. };
  1067. // a - d
  1068. // | |
  1069. // b - c
  1070. //
  1071. // [( a, b, c, d ) ...........
  1072. // [( a, b, c ), (a, c, d )....
  1073. // Also keep track of original poly index.
  1074. Geometry.prototype.convertPolyIndicesToTri = function ( indices, strides ) {
  1075. var res = [];
  1076. var i = 0;
  1077. var currentPolyNum = 0;
  1078. var currentStride = 0;
  1079. var polyIndices = [];
  1080. while ( i < indices.length ) {
  1081. currentStride = strides[ currentPolyNum ];
  1082. // CAUTIN: NG over 6gon
  1083. for ( var j = 0; j <= ( currentStride - 3 ); j ++ ) {
  1084. res.push( indices[ i ] );
  1085. res.push( indices[ i + ( currentStride - 2 - j ) ] );
  1086. res.push( indices[ i + ( currentStride - 1 - j ) ] );
  1087. polyIndices.push(currentPolyNum);
  1088. }
  1089. currentPolyNum ++;
  1090. i += currentStride;
  1091. }
  1092. return {res: res, polyIndices: polyIndices};
  1093. };
  1094. Geometry.prototype.addBones = function ( bones ) {
  1095. this.bones = bones;
  1096. };
  1097. function UV() {
  1098. this.uv = null;
  1099. this.map = null;
  1100. this.ref = null;
  1101. this.node = null;
  1102. this.index = null;
  1103. }
  1104. UV.prototype.getUV = function ( node ) {
  1105. if ( this.node && this.uv && this.map && this.ref ) {
  1106. return this.uv;
  1107. } else {
  1108. return this._parseText( node );
  1109. }
  1110. };
  1111. UV.prototype.getMap = function ( node ) {
  1112. if ( this.node && this.uv && this.map && this.ref ) {
  1113. return this.map;
  1114. } else {
  1115. this._parseText( node );
  1116. return this.map;
  1117. }
  1118. };
  1119. UV.prototype.getRef = function ( node ) {
  1120. if ( this.node && this.uv && this.map && this.ref ) {
  1121. return this.ref;
  1122. } else {
  1123. this._parseText( node );
  1124. return this.ref;
  1125. }
  1126. };
  1127. UV.prototype.getIndex = function ( node ) {
  1128. if ( this.node && this.uv && this.map && this.ref ) {
  1129. return this.index;
  1130. } else {
  1131. this._parseText( node );
  1132. return this.index;
  1133. }
  1134. };
  1135. UV.prototype.getNode = function ( topnode ) {
  1136. if ( this.node !== null ) {
  1137. return this.node;
  1138. }
  1139. this.node = topnode.subNodes.LayerElementUV;
  1140. return this.node;
  1141. };
  1142. UV.prototype._parseText = function ( node ) {
  1143. var uvNode = this.getNode( node );
  1144. if ( uvNode === undefined ) {
  1145. // console.log( node.attrName + "(" + node.id + ")" + " has no LayerElementUV." );
  1146. return [];
  1147. }
  1148. var count = 0;
  1149. var x = '';
  1150. for ( var n in uvNode ) {
  1151. if ( n.match( /^\d+$/ ) ) {
  1152. count ++;
  1153. x = n;
  1154. }
  1155. }
  1156. if ( count > 0 ) {
  1157. console.warn( 'multi uv not supported' );
  1158. uvNode = uvNode[ n ];
  1159. }
  1160. var uvIndex = uvNode.subNodes.UVIndex.properties.a;
  1161. var uvs = uvNode.subNodes.UV.properties.a;
  1162. var uvMap = uvNode.properties.MappingInformationType;
  1163. var uvRef = uvNode.properties.ReferenceInformationType;
  1164. this.uv = toFloat( uvs.split( ',' ) );
  1165. this.index = toInt( uvIndex.split( ',' ) );
  1166. this.map = uvMap; // TODO: normalize notation shaking... FOR BLENDER
  1167. this.ref = uvRef;
  1168. return this.uv;
  1169. };
  1170. UV.prototype.parse = function ( node, geo ) {
  1171. this.uvNode = this.getNode( node );
  1172. this.uv = this.getUV( node );
  1173. var mappingType = this.getMap( node );
  1174. var refType = this.getRef( node );
  1175. var indices = this.getIndex( node );
  1176. var strides = geo.getPolygonTopologyArray();
  1177. // it means that there is a normal for every vertex of every polygon of the model.
  1178. // For example, if the models has 8 vertices that make up four quads, then there
  1179. // will be 16 normals (one normal * 4 polygons * 4 vertices of the polygon). Note
  1180. // that generally a game engine needs the vertices to have only one normal defined.
  1181. // So, if you find a vertex has more tha one normal, you can either ignore the normals
  1182. // you find after the first, or calculate the mean from all of them (normal smoothing).
  1183. //if ( mappingType == "ByPolygonVertex" ){
  1184. switch ( mappingType ) {
  1185. case "ByPolygonVertex":
  1186. switch ( refType ) {
  1187. // Direct
  1188. // The this.uv are in order.
  1189. case "Direct":
  1190. this.uv = this.parseUV_ByPolygonVertex_Direct( this.uv, indices, strides, 2 );
  1191. break;
  1192. // IndexToDirect
  1193. // The order of the this.uv is given by the uvsIndex property.
  1194. case "IndexToDirect":
  1195. this.uv = this.parseUV_ByPolygonVertex_IndexToDirect( this.uv, indices );
  1196. break;
  1197. }
  1198. // convert from by polygon(vert) data into by verts data
  1199. this.uv = mapByPolygonVertexToByVertex( this.uv, geo.getPolygonVertexIndices( node ), 2 );
  1200. break;
  1201. case "ByPolygon":
  1202. switch ( refType ) {
  1203. // Direct
  1204. // The this.uv are in order.
  1205. case "Direct":
  1206. this.uv = this.parseUV_ByPolygon_Direct();
  1207. break;
  1208. // IndexToDirect
  1209. // The order of the this.uv is given by the uvsIndex property.
  1210. case "IndexToDirect":
  1211. this.uv = this.parseUV_ByPolygon_IndexToDirect();
  1212. break;
  1213. }
  1214. break;
  1215. }
  1216. return this.uv;
  1217. };
  1218. UV.prototype.parseUV_ByPolygonVertex_Direct = function ( node, indices, strides, itemSize ) {
  1219. return parse_Data_ByPolygonVertex_Direct( node, indices, strides, itemSize );
  1220. };
  1221. UV.prototype.parseUV_ByPolygonVertex_IndexToDirect = function ( node, indices ) {
  1222. return parse_Data_ByPolygonVertex_IndexToDirect( node, indices, 2 );
  1223. };
  1224. UV.prototype.parseUV_ByPolygon_Direct = function ( node ) {
  1225. console.warn( "not implemented" );
  1226. return node;
  1227. };
  1228. UV.prototype.parseUV_ByPolygon_IndexToDirect = function ( node ) {
  1229. console.warn( "not implemented" );
  1230. return node;
  1231. };
  1232. UV.prototype.parseUV_ByVertex_Direct = function ( node ) {
  1233. console.warn( "not implemented" );
  1234. return node;
  1235. };
  1236. function Normal() {
  1237. this.normal = null;
  1238. this.map = null;
  1239. this.ref = null;
  1240. this.node = null;
  1241. this.index = null;
  1242. }
  1243. Normal.prototype.getNormal = function ( node ) {
  1244. if ( this.node && this.normal && this.map && this.ref ) {
  1245. return this.normal;
  1246. } else {
  1247. this._parseText( node );
  1248. return this.normal;
  1249. }
  1250. };
  1251. // mappingType: possible variant
  1252. // ByPolygon
  1253. // ByPolygonVertex
  1254. // ByVertex (or also ByVertice, as the Blender exporter writes)
  1255. // ByEdge
  1256. // AllSame
  1257. // var mappingType = node.properties.MappingInformationType;
  1258. Normal.prototype.getMap = function ( node ) {
  1259. if ( this.node && this.normal && this.map && this.ref ) {
  1260. return this.map;
  1261. } else {
  1262. this._parseText( node );
  1263. return this.map;
  1264. }
  1265. };
  1266. // refType: possible variants
  1267. // Direct
  1268. // IndexToDirect (or Index for older versions)
  1269. // var refType = node.properties.ReferenceInformationType;
  1270. Normal.prototype.getRef = function ( node ) {
  1271. if ( this.node && this.normal && this.map && this.ref ) {
  1272. return this.ref;
  1273. } else {
  1274. this._parseText( node );
  1275. return this.ref;
  1276. }
  1277. };
  1278. Normal.prototype.getNode = function ( node ) {
  1279. if ( this.node ) {
  1280. return this.node;
  1281. }
  1282. this.node = node.subNodes.LayerElementNormal;
  1283. return this.node;
  1284. };
  1285. Normal.prototype._parseText = function ( node ) {
  1286. var normalNode = this.getNode( node );
  1287. if ( normalNode === undefined ) {
  1288. console.warn( 'node: ' + node.attrName + "(" + node.id + ") does not have LayerElementNormal" );
  1289. return;
  1290. }
  1291. var mappingType = normalNode.properties.MappingInformationType;
  1292. var refType = normalNode.properties.ReferenceInformationType;
  1293. var rawTextNormals = normalNode.subNodes.Normals.properties.a;
  1294. this.normal = toFloat( rawTextNormals.split( ',' ) );
  1295. // TODO: normalize notation shaking, vertex / vertice... blender...
  1296. this.map = mappingType;
  1297. this.ref = refType;
  1298. };
  1299. Normal.prototype.parse = function ( topnode, geo ) {
  1300. var normals = this.getNormal( topnode );
  1301. var normalNode = this.getNode( topnode );
  1302. var mappingType = this.getMap( topnode );
  1303. var refType = this.getRef( topnode );
  1304. var indices = geo.getPolygonVertexIndices( topnode );
  1305. var strides = geo.getPolygonTopologyArray( topnode );
  1306. // it means that there is a normal for every vertex of every polygon of the model.
  1307. // For example, if the models has 8 vertices that make up four quads, then there
  1308. // will be 16 normals (one normal * 4 polygons * 4 vertices of the polygon). Note
  1309. // that generally a game engine needs the vertices to have only one normal defined.
  1310. // So, if you find a vertex has more tha one normal, you can either ignore the normals
  1311. // you find after the first, or calculate the mean from all of them (normal smoothing).
  1312. //if ( mappingType == "ByPolygonVertex" ){
  1313. switch ( mappingType ) {
  1314. case "ByPolygonVertex":
  1315. switch ( refType ) {
  1316. // Direct
  1317. // The normals are in order.
  1318. case "Direct":
  1319. normals = this.parseNormal_ByPolygonVertex_Direct( normals, indices, strides, 3 );
  1320. break;
  1321. // IndexToDirect
  1322. // The order of the normals is given by the NormalsIndex property.
  1323. case "IndexToDirect":
  1324. normals = this.parseNormal_ByPolygonVertex_IndexToDirect();
  1325. break;
  1326. }
  1327. break;
  1328. case "ByPolygon":
  1329. switch ( refType ) {
  1330. // Direct
  1331. // The normals are in order.
  1332. case "Direct":
  1333. normals = this.parseNormal_ByPolygon_Direct();
  1334. break;
  1335. // IndexToDirect
  1336. // The order of the normals is given by the NormalsIndex property.
  1337. case "IndexToDirect":
  1338. normals = this.parseNormal_ByPolygon_IndexToDirect();
  1339. break;
  1340. }
  1341. break;
  1342. }
  1343. return normals;
  1344. };
  1345. Normal.prototype.parseNormal_ByPolygonVertex_Direct = function ( node, indices, strides, itemSize ) {
  1346. return parse_Data_ByPolygonVertex_Direct( node, indices, strides, itemSize );
  1347. };
  1348. Normal.prototype.parseNormal_ByPolygonVertex_IndexToDirect = function ( node ) {
  1349. console.warn( "not implemented" );
  1350. return node;
  1351. };
  1352. Normal.prototype.parseNormal_ByPolygon_Direct = function ( node ) {
  1353. console.warn( "not implemented" );
  1354. return node;
  1355. };
  1356. Normal.prototype.parseNormal_ByPolygon_IndexToDirect = function ( node ) {
  1357. console.warn( "not implemented" );
  1358. return node;
  1359. };
  1360. Normal.prototype.parseNormal_ByVertex_Direct = function ( node ) {
  1361. console.warn( "not implemented" );
  1362. return node;
  1363. };
  1364. function AnimationCurve() {
  1365. this.version = null;
  1366. this.id = null;
  1367. this.internalId = null;
  1368. this.times = null;
  1369. this.values = null;
  1370. this.attrFlag = null; // tangeant
  1371. this.attrData = null; // slope, weight
  1372. }
  1373. AnimationCurve.prototype.fromNode = function ( curveNode ) {
  1374. this.id = curveNode.id;
  1375. this.internalId = curveNode.id;
  1376. this.times = curveNode.subNodes.KeyTime.properties.a;
  1377. this.values = curveNode.subNodes.KeyValueFloat.properties.a;
  1378. this.attrFlag = curveNode.subNodes.KeyAttrFlags.properties.a;
  1379. this.attrData = curveNode.subNodes.KeyAttrDataFloat.properties.a;
  1380. this.times = toFloat( this.times.split( ',' ) );
  1381. this.values = toFloat( this.values.split( ',' ) );
  1382. this.attrData = toFloat( this.attrData.split( ',' ) );
  1383. this.attrFlag = toInt( this.attrFlag.split( ',' ) );
  1384. this.times = this.times.map( function ( element ) {
  1385. return FBXTimeToSeconds( element );
  1386. } );
  1387. return this;
  1388. };
  1389. AnimationCurve.prototype.getLength = function () {
  1390. return this.times[ this.times.length - 1 ];
  1391. };
  1392. function AnimationNode() {
  1393. this.id = null;
  1394. this.attr = null; // S, R, T
  1395. this.attrX = false;
  1396. this.attrY = false;
  1397. this.attrZ = false;
  1398. this.internalId = null;
  1399. this.containerInternalId = null; // bone, null etc Id
  1400. this.containerBoneId = null; // bone, null etc Id
  1401. this.curveIdx = null; // AnimationCurve's indices
  1402. this.curves = []; // AnimationCurve refs
  1403. }
  1404. AnimationNode.prototype.fromNode = function ( allNodes, node, bones ) {
  1405. this.id = node.id;
  1406. this.attr = node.attrName;
  1407. this.internalId = node.id;
  1408. if ( this.attr.match( /S|R|T/ ) ) {
  1409. for ( var attrKey in node.properties ) {
  1410. if ( attrKey.match( /X/ ) ) {
  1411. this.attrX = true;
  1412. }
  1413. if ( attrKey.match( /Y/ ) ) {
  1414. this.attrY = true;
  1415. }
  1416. if ( attrKey.match( /Z/ ) ) {
  1417. this.attrZ = true;
  1418. }
  1419. }
  1420. } else {
  1421. // may be deform percent nodes
  1422. return null;
  1423. }
  1424. this.containerIndices = allNodes.searchConnectionParent( this.id );
  1425. this.curveIdx = allNodes.searchConnectionChildren( this.id );
  1426. for ( var i = this.containerIndices.length - 1; i >= 0; -- i ) {
  1427. var boneId = bones.searchRealId( this.containerIndices[ i ] );
  1428. if ( boneId >= 0 ) {
  1429. this.containerBoneId = boneId;
  1430. this.containerId = this.containerIndices [ i ];
  1431. }
  1432. if ( boneId >= 0 ) {
  1433. break;
  1434. }
  1435. }
  1436. // this.containerBoneId = bones.searchRealId( this.containerIndices );
  1437. return this;
  1438. };
  1439. AnimationNode.prototype.setCurve = function ( curve ) {
  1440. this.curves.push( curve );
  1441. };
  1442. function Animation() {
  1443. this.curves = {};
  1444. this.length = 0.0;
  1445. this.fps = 30.0;
  1446. this.frames = 0.0;
  1447. }
  1448. Animation.prototype.parse = function ( node, bones ) {
  1449. var rawNodes = node.Objects.subNodes.AnimationCurveNode;
  1450. var rawCurves = node.Objects.subNodes.AnimationCurve;
  1451. // first: expand AnimationCurveNode into curve nodes
  1452. var curveNodes = [];
  1453. for ( var key in rawNodes ) {
  1454. if ( key.match( /\d+/ ) ) {
  1455. var a = ( new AnimationNode() ).fromNode( node, rawNodes[ key ], bones );
  1456. curveNodes.push( a );
  1457. }
  1458. }
  1459. // second: gen dict, mapped by internalId
  1460. var tmp = {};
  1461. for ( var i = 0; i < curveNodes.length; ++ i ) {
  1462. if ( curveNodes[ i ] === null ) {
  1463. continue;
  1464. }
  1465. tmp[ curveNodes[ i ].id ] = curveNodes[ i ];
  1466. }
  1467. // third: insert curves into the dict
  1468. var ac = [];
  1469. var max = 0.0;
  1470. for ( key in rawCurves ) {
  1471. if ( key.match( /\d+/ ) ) {
  1472. var c = ( new AnimationCurve() ).fromNode( rawCurves[ key ] );
  1473. ac.push( c );
  1474. max = c.getLength() ? c.getLength() : max;
  1475. var parentId = node.searchConnectionParent( c.id )[ 0 ];
  1476. var axis = node.searchConnectionType( c.id, parentId );
  1477. if ( axis.match( /X/ ) ) {
  1478. axis = 'x';
  1479. }
  1480. if ( axis.match( /Y/ ) ) {
  1481. axis = 'y';
  1482. }
  1483. if ( axis.match( /Z/ ) ) {
  1484. axis = 'z';
  1485. }
  1486. tmp[ parentId ].curves[ axis ] = c;
  1487. }
  1488. }
  1489. // forth:
  1490. for ( var t in tmp ) {
  1491. var id = tmp[ t ].containerBoneId;
  1492. if ( this.curves[ id ] === undefined ) {
  1493. this.curves[ id ] = {};
  1494. }
  1495. this.curves[ id ][ tmp[ t ].attr ] = tmp[ t ];
  1496. }
  1497. this.length = max;
  1498. this.frames = this.length * this.fps;
  1499. return this;
  1500. };
  1501. function Textures() {
  1502. this.textures = [];
  1503. this.perGeoMap = {};
  1504. }
  1505. Textures.prototype.add = function ( tex ) {
  1506. if ( this.textures === undefined ) {
  1507. this.textures = [];
  1508. }
  1509. this.textures.push( tex );
  1510. for ( var i = 0; i < tex.parentIds.length; ++ i ) {
  1511. if ( this.perGeoMap[ tex.parentIds[ i ] ] === undefined ) {
  1512. this.perGeoMap[ tex.parentIds[ i ] ] = [];
  1513. }
  1514. this.perGeoMap[ tex.parentIds[ i ] ].push( this.textures[ this.textures.length - 1 ] );
  1515. }
  1516. };
  1517. Textures.prototype.parse = function ( node, bones ) {
  1518. var rawNodes = node.Objects.subNodes.Texture;
  1519. for ( var n in rawNodes ) {
  1520. var tex = ( new Texture() ).parse( rawNodes[ n ], node );
  1521. this.add( tex );
  1522. }
  1523. return this;
  1524. };
  1525. Textures.prototype.getById = function ( id ) {
  1526. return this.perGeoMap[ id ];
  1527. };
  1528. function Texture() {
  1529. this.fileName = "";
  1530. this.name = "";
  1531. this.id = null;
  1532. this.parentIds = [];
  1533. }
  1534. Texture.prototype.parse = function ( node, nodes ) {
  1535. this.id = node.id;
  1536. this.name = node.attrName;
  1537. this.fileName = this.parseFileName( node.properties.FileName );
  1538. this.parentIds = this.searchParents( this.id, nodes );
  1539. return this;
  1540. };
  1541. // TODO: support directory
  1542. Texture.prototype.parseFileName = function ( fname ) {
  1543. if ( fname === undefined ) {
  1544. return "";
  1545. }
  1546. // ignore directory structure, flatten path
  1547. var splitted = fname.split( /[\\\/]/ );
  1548. if ( splitted.length > 0 ) {
  1549. return splitted[ splitted.length - 1 ];
  1550. } else {
  1551. return fname;
  1552. }
  1553. };
  1554. Texture.prototype.searchParents = function ( id, nodes ) {
  1555. var p = nodes.searchConnectionParent( id );
  1556. return p;
  1557. };
  1558. function Materials() {
  1559. this.materials = [];
  1560. this.perGeoMap = {};
  1561. }
  1562. Materials.prototype.add = function ( mat ) {
  1563. if ( this.materials === undefined ) {
  1564. this.materials = [];
  1565. }
  1566. this.materials.push( mat );
  1567. for ( var i = 0; i < mat.parentIds.length; ++ i ) {
  1568. if ( this.perGeoMap[ mat.parentIds[ i ] ] === undefined ) {
  1569. this.perGeoMap[ mat.parentIds[ i ] ] = [];
  1570. }
  1571. this.perGeoMap[ mat.parentIds[ i ] ].push( this.materials[ this.materials.length - 1 ] );
  1572. }
  1573. };
  1574. Materials.prototype.parse = function ( node, bones ) {
  1575. var rawNodes = node.Objects.subNodes.Material;
  1576. for ( var n in rawNodes ) {
  1577. var mat = ( new Material() ).parse( rawNodes[ n ], node );
  1578. this.add( mat );
  1579. }
  1580. return this;
  1581. };
  1582. Materials.prototype.getById = function ( id ) {
  1583. return this.perGeoMap[ id ];
  1584. };
  1585. function Material() {
  1586. this.fileName = "";
  1587. this.name = "";
  1588. this.id = null;
  1589. this.parentIds = [];
  1590. }
  1591. Material.prototype.parse = function ( node, nodes ) {
  1592. this.id = node.id;
  1593. this.name = node.attrName;
  1594. this.type = node.properties.ShadingModel;
  1595. this.parameters = this.getParameters( node.properties );
  1596. this.parentIds = this.searchParents( this.id, nodes );
  1597. return this;
  1598. };
  1599. Material.prototype.getParameters = function( properties ) {
  1600. var parameters = {};
  1601. //TODO: Missing parameters:
  1602. // - Ambient
  1603. // - AmbientColor
  1604. // - (Diffuse?) Using DiffuseColor, which has same value, so I dunno.
  1605. // - (Emissive?) Same as above)
  1606. // - MultiLayer
  1607. // - ShininessExponent (Same vals as Shininess)
  1608. // - Specular (Same vals as SpecularColor)
  1609. // - TransparencyFactor (Maybe same as Opacity?).
  1610. parameters.color = new THREE.Color().fromArray(toFloat([properties.DiffuseColor.value.x, properties.DiffuseColor.value.y, properties.DiffuseColor.value.z]));
  1611. parameters.specular = new THREE.Color().fromArray(toFloat([properties.SpecularColor.value.x, properties.SpecularColor.value.y, properties.SpecularColor.value.z]));
  1612. parameters.shininess = properties.Shininess.value;
  1613. parameters.emissive = new THREE.Color().fromArray(toFloat([properties.EmissiveColor.value.x, properties.EmissiveColor.value.y, properties.EmissiveColor.value.z]));
  1614. parameters.emissiveIntensity = properties.EmissiveFactor.value;
  1615. parameters.reflectivity = properties.Reflectivity.value;
  1616. parameters.opacity = properties.Opacity.value;
  1617. if(parameters.opacity < 1.0) {
  1618. parameters.transparent = true;
  1619. }
  1620. return parameters;
  1621. };
  1622. Material.prototype.searchParents = function ( id, nodes ) {
  1623. var p = nodes.searchConnectionParent( id );
  1624. return p;
  1625. };
  1626. /* --------------------------------------------------------------------- */
  1627. /* --------------------------------------------------------------------- */
  1628. /* --------------------------------------------------------------------- */
  1629. /* --------------------------------------------------------------------- */
  1630. function loadTextureImage( texture, url ) {
  1631. var loader = new THREE.ImageLoader();
  1632. loader.load( url, function ( image ) {
  1633. } );
  1634. loader.load( url, function ( image ) {
  1635. texture.image = image;
  1636. texture.needUpdate = true;
  1637. console.log( 'tex load done' );
  1638. },
  1639. // Function called when download progresses
  1640. function ( xhr ) {
  1641. console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
  1642. },
  1643. // Function called when download errors
  1644. function ( xhr ) {
  1645. console.log( 'An error happened' );
  1646. }
  1647. );
  1648. }
  1649. // LayerElementUV: 0 {
  1650. // Version: 101
  1651. // Name: "Texture_Projection"
  1652. // MappingInformationType: "ByPolygonVertex"
  1653. // ReferenceInformationType: "IndexToDirect"
  1654. // UV: *1746 {
  1655. // UVIndex: *7068 {
  1656. //
  1657. // The order of the uvs is given by the UVIndex property.
  1658. function parse_Data_ByPolygonVertex_IndexToDirect( node, indices, itemSize ) {
  1659. var res = [];
  1660. for ( var i = 0; i < indices.length; ++ i ) {
  1661. for ( var j = 0; j < itemSize; ++ j ) {
  1662. res.push( node[ ( indices[ i ] * itemSize ) + j ] );
  1663. }
  1664. }
  1665. return res;
  1666. }
  1667. // what want: normal per vertex, order vertice
  1668. // i have: normal per polygon
  1669. // i have: indice per polygon
  1670. var parse_Data_ByPolygonVertex_Direct = function ( node, indices, strides, itemSize ) {
  1671. // *21204 > 3573
  1672. // Geometry: 690680816, "Geometry::", "Mesh" {
  1673. // Vertices: *3573 {
  1674. // PolygonVertexIndex: *7068 {
  1675. var tmp = [];
  1676. var currentIndex = 0;
  1677. // first: sort to per vertex
  1678. for ( var i = 0; i < indices.length; ++ i ) {
  1679. tmp[ indices[ i ] ] = [];
  1680. // TODO: duped entry? blend or something?
  1681. for ( var s = 0; s < itemSize; ++ s ) {
  1682. tmp[ indices[ i ] ][ s ] = node[ currentIndex + s ];
  1683. }
  1684. currentIndex += itemSize;
  1685. }
  1686. // second: expand x,y,z into serial array
  1687. var res = [];
  1688. for ( var jj = 0; jj < tmp.length; ++ jj ) {
  1689. if ( tmp[ jj ] === undefined ) {
  1690. continue;
  1691. }
  1692. for ( var t = 0; t < itemSize; ++ t ) {
  1693. if ( tmp[ jj ][ t ] === undefined ) {
  1694. continue;
  1695. }
  1696. res.push( tmp[ jj ][ t ] );
  1697. }
  1698. }
  1699. return res;
  1700. };
  1701. // convert from by polygon(vert) data into by verts data
  1702. function mapByPolygonVertexToByVertex( data, indices, stride ) {
  1703. var tmp = {};
  1704. var res = [];
  1705. var max = 0;
  1706. for ( var i = 0; i < indices.length; ++ i ) {
  1707. if ( indices[ i ] in tmp ) {
  1708. continue;
  1709. }
  1710. tmp[ indices[ i ] ] = {};
  1711. for ( var j = 0; j < stride; ++ j ) {
  1712. tmp[ indices[ i ] ][ j ] = data[ i * stride + j ];
  1713. }
  1714. max = max < indices[ i ] ? indices[ i ] : max;
  1715. }
  1716. try {
  1717. for ( i = 0; i <= max; i ++ ) {
  1718. for ( var s = 0; s < stride; s ++ ) {
  1719. res.push( tmp[ i ][ s ] );
  1720. }
  1721. }
  1722. } catch ( e ) {
  1723. //console.log( max );
  1724. //console.log( tmp );
  1725. //console.log( i );
  1726. //console.log( e );
  1727. }
  1728. return res;
  1729. }
  1730. // AUTODESK uses broken clock. i guess
  1731. var FBXTimeToSeconds = function ( adskTime ) {
  1732. return adskTime / 46186158000;
  1733. };
  1734. var degToRad = function ( degrees ) {
  1735. return degrees * Math.PI / 180;
  1736. };
  1737. var radToDeg = function ( radians ) {
  1738. return radians * 180 / Math.PI;
  1739. };
  1740. var quatFromVec = function ( x, y, z ) {
  1741. var euler = new THREE.Euler( x, y, z, 'ZYX' );
  1742. var quat = new THREE.Quaternion();
  1743. quat.setFromEuler( euler );
  1744. return quat;
  1745. };
  1746. // extend Array.prototype ? ....uuuh
  1747. var toInt = function ( arr ) {
  1748. return arr.map( function ( element ) {
  1749. return parseInt( element );
  1750. } );
  1751. };
  1752. var toFloat = function ( arr ) {
  1753. return arr.map( function ( element ) {
  1754. return parseFloat( element );
  1755. } );
  1756. };
  1757. var toRad = function ( arr ) {
  1758. return arr.map( function ( element ) {
  1759. return degToRad( element );
  1760. } );
  1761. };
  1762. var toMat44 = function ( arr ) {
  1763. var mat = new THREE.Matrix4();
  1764. mat.set(
  1765. arr[ 0 ], arr[ 4 ], arr[ 8 ], arr[ 12 ],
  1766. arr[ 1 ], arr[ 5 ], arr[ 9 ], arr[ 13 ],
  1767. arr[ 2 ], arr[ 6 ], arr[ 10 ], arr[ 14 ],
  1768. arr[ 3 ], arr[ 7 ], arr[ 11 ], arr[ 15 ]
  1769. );
  1770. /*
  1771. mat.set(
  1772. arr[ 0], arr[ 1], arr[ 2], arr[ 3],
  1773. arr[ 4], arr[ 5], arr[ 6], arr[ 7],
  1774. arr[ 8], arr[ 9], arr[10], arr[11],
  1775. arr[12], arr[13], arr[14], arr[15]
  1776. );
  1777. // */
  1778. return mat;
  1779. };
  1780. } )();