FBXSceneEncoder.cpp 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797
  1. #ifdef USE_FBX
  2. #include <algorithm>
  3. #include <string>
  4. #include "FBXSceneEncoder.h"
  5. #include "EncoderArguments.h"
  6. using namespace gameplay;
  7. /**
  8. * Returns the aspect ratio from the given camera.
  9. *
  10. * @param fbxCamera The FBX camera to get the aspect ratio from.
  11. *
  12. * @return The aspect ratio from the camera.
  13. */
  14. static float getAspectRatio(FbxCamera* fbxCamera);
  15. /**
  16. * Returns the field of view Y from the given camera.
  17. *
  18. * @param fbxCamera The camera to get the fiew of view from.
  19. *
  20. * @return The field of view Y.
  21. */
  22. static float getFieldOfView(FbxCamera* fbxCamera);
  23. /**
  24. * Loads the texture coordinates from given mesh's polygon part into the vertex.
  25. *
  26. * @param fbxMesh The mesh to get the polygon from.
  27. * @param uvs The UV list to load tex coords from.
  28. * @param uvSetIndex The UV set index of the uvs.
  29. * @param polyIndex The index of the polygon in the mesh.
  30. * @param posInPoly The position of the vertex in the polygon.
  31. * @param meshVertexIndex The index of the vertex in the mesh.
  32. * @param vertex The vertex to copy the texture coordinates to.
  33. */
  34. static void loadTextureCoords(FbxMesh* fbxMesh, const FbxGeometryElementUV* uvs, int uvSetIndex, int polyIndex, int posInPoly, int meshVertexIndex, Vertex* vertex);
  35. /**
  36. * Loads the normal from the mesh and adds it to the given vertex.
  37. *
  38. * @param fbxMesh The mesh to get the polygon from.
  39. * @param vertexIndex The vertex index in the mesh.
  40. * @param controlPointIndex The control point index.
  41. * @param vertex The vertex to copy to.
  42. */
  43. static void loadNormal(FbxMesh* fbxMesh, int vertexIndex, int controlPointIndex, Vertex* vertex);
  44. /**
  45. * Loads the tangent from the mesh and adds it to the given vertex.
  46. *
  47. * @param fbxMesh The mesh to load from.
  48. * @param vertexIndex The index of the vertex within fbxMesh.
  49. * @param controlPointIndex The control point index.
  50. * @param vertex The vertex to copy to.
  51. */
  52. static void loadTangent(FbxMesh* fbxMesh, int vertexIndex, int controlPointIndex, Vertex* vertex);
  53. /**
  54. * Loads the binormal from the mesh and adds it to the given vertex.
  55. *
  56. * @param fbxMesh The mesh to load from.
  57. * @param vertexIndex The index of the vertex within fbxMesh.
  58. * @param controlPointIndex The control point index.
  59. * @param vertex The vertex to copy to.
  60. */
  61. static void loadBinormal(FbxMesh* fbxMesh, int vertexIndex, int controlPointIndex, Vertex* vertex);
  62. /**
  63. * Loads the vertex diffuse color from the mesh and adds it to the given vertex.
  64. *
  65. * @param fbxMesh The mesh to load from.
  66. * @param vertexIndex The index of the vertex within fbxMesh.
  67. * @param controlPointIndex The control point index.
  68. * @param vertex The vertex to copy to.
  69. */
  70. static void loadVertexColor(FbxMesh* fbxMesh, int vertexIndex, int controlPointIndex, Vertex* vertex);
  71. /**
  72. * Loads the blend weight and blend indices data into the vertex.
  73. *
  74. * @param vertexWeights List of vertex weights. The x member contains the blendIndices. The y member contains the blendWeights.
  75. * @param vertex The vertex to copy the blend data to.
  76. */
  77. static void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex);
  78. /**
  79. * Loads the blend weights and blend indices from the given mesh.
  80. *
  81. * Each element of weights is a list of Vector2s where "x" is the blend index and "y" is the blend weight.
  82. *
  83. * @param fbxMesh The mesh to load from.
  84. * @param weights List of blend weights and blend indices for each vertex.
  85. *
  86. * @return True if this mesh has a mesh skin, false otherwise.
  87. */
  88. static bool loadBlendWeights(FbxMesh* fbxMesh, std::vector<std::vector<Vector2> >& weights);
  89. /**
  90. * Copies from an FBX matrix to a float[16] array.
  91. */
  92. static void copyMatrix(const FbxMatrix& fbxMatrix, float* matrix);
  93. /**
  94. * Copies from an FBX matrix to a gameplay matrix.
  95. */
  96. static void copyMatrix(const FbxMatrix& fbxMatrix, Matrix& matrix);
  97. /**
  98. * Finds the min and max start time and stop time of the given animation curve.
  99. *
  100. * startTime is updated if the animation curve contains a start time that is less than startTime.
  101. * stopTime is updated if the animation curve contains a stop time that is greater than stopTime.
  102. * frameRate is updated if the animation curve contains a frame rate that is greater than frameRate.
  103. *
  104. * @param animCurve The animation curve to read from.
  105. * @param startTime The min start time. (in/out)
  106. * @param stopTime The max stop time. (in/out)
  107. * @param frameRate The frame rate. (in/out)
  108. */
  109. static void findMinMaxTime(FbxAnimCurve* animCurve, float* startTime, float* stopTime, float* frameRate);
  110. /**
  111. * Appends key frame data to the given node for the specified animation target attribute.
  112. *
  113. * @param fbxNode The node to get the matrix transform from.
  114. * @param channel The aniamtion channel to write values into.
  115. * @param time The time of the keyframe.
  116. * @param scale The evaluated scale for the keyframe.
  117. * @param rotation The evalulated rotation for the keyframe.
  118. * @param translation The evalulated translation for the keyframe.
  119. */
  120. static void appendKeyFrame(FbxNode* fbxNode, AnimationChannel* channel, float time, const Vector3& scale, const Quaternion& rotation, const Vector3& translation);
  121. /**
  122. * Decomposes the given node's matrix transform at the given time and copies to scale, rotation and translation.
  123. *
  124. * @param fbxNode The node to get the matrix transform from.
  125. * @param time The time to get the matrix transform from.
  126. * @param scale The scale to copy to.
  127. * @param rotation The rotation to copy to.
  128. * @param translation The translation to copy to.
  129. */
  130. static void decompose(FbxNode* fbxNode, float time, Vector3* scale, Quaternion* rotation, Vector3* translation);
  131. /**
  132. * Creates an animation channel that targets the given node and target attribute using the given key times and key values.
  133. *
  134. * @param fbxNode The node to target.
  135. * @param targetAttrib The attribute type to target.
  136. * @param keyTimes The key times for the animation channel.
  137. * @param keyValues The key values for the animation channel.
  138. *
  139. * @return The newly created animation channel.
  140. */
  141. static AnimationChannel* createAnimationChannel(FbxNode* fbxNode, unsigned int targetAttrib, const std::vector<float>& keyTimes, const std::vector<float>& keyValues);
  142. void addScaleChannel(Animation* animation, FbxNode* fbxNode, float startTime, float stopTime);
  143. void addTranslateChannel(Animation* animation, FbxNode* fbxNode, float startTime, float stopTime);
  144. /**
  145. * Determines if it is possible to automatically group animations for mesh skins.
  146. *
  147. * @param fbxScene The FBX scene to search.
  148. *
  149. * @return True if there is at least one mesh skin that has animations that can be grouped.
  150. */
  151. bool isGroupAnimationPossible(FbxScene* fbxScene);
  152. bool isGroupAnimationPossible(FbxNode* fbxNode);
  153. bool isGroupAnimationPossible(FbxMesh* fbxMesh);
  154. FbxAnimCurve* getCurve(FbxPropertyT<FbxDouble3>& prop, FbxAnimLayer* animLayer, const char* pChannel)
  155. {
  156. #if FBXSDK_VERSION_MAJOR == 2013 && FBXSDK_VERSION_MINOR == 1
  157. return prop.GetCurve<FbxAnimCurve>(animLayer, pChannel);
  158. #else
  159. return prop.GetCurve(animLayer, pChannel);
  160. #endif
  161. }
  162. ////////////////////////////////////
  163. // Member Functions
  164. ////////////////////////////////////
  165. FBXSceneEncoder::FBXSceneEncoder()
  166. : _groupAnimation(NULL), _autoGroupAnimations(false)
  167. {
  168. }
  169. FBXSceneEncoder::~FBXSceneEncoder()
  170. {
  171. }
  172. void FBXSceneEncoder::write(const std::string& filepath, const EncoderArguments& arguments)
  173. {
  174. FbxManager* sdkManager = FbxManager::Create();
  175. FbxIOSettings *ios = FbxIOSettings::Create(sdkManager, IOSROOT);
  176. sdkManager->SetIOSettings(ios);
  177. FbxImporter* importer = FbxImporter::Create(sdkManager,"");
  178. if (!importer->Initialize(filepath.c_str(), -1, sdkManager->GetIOSettings()))
  179. {
  180. LOG(1, "Call to FbxImporter::Initialize() failed.\n");
  181. LOG(1, "Error returned: %s\n\n", importer->GetLastErrorString());
  182. exit(-1);
  183. }
  184. FbxScene* fbxScene = FbxScene::Create(sdkManager,"__FBX_SCENE__");
  185. print("Loading FBX file.");
  186. importer->Import(fbxScene);
  187. importer->Destroy();
  188. // Determine if animations should be grouped.
  189. if (arguments.getGroupAnimationAnimationId().empty() && isGroupAnimationPossible(fbxScene))
  190. {
  191. if (promptUserGroupAnimations())
  192. {
  193. _autoGroupAnimations = true;
  194. }
  195. }
  196. print("Loading Scene.");
  197. loadScene(fbxScene);
  198. print("Loading animations.");
  199. loadAnimations(fbxScene, arguments);
  200. sdkManager->Destroy();
  201. print("Optimizing GamePlay Binary.");
  202. _gamePlayFile.adjust();
  203. if (_autoGroupAnimations)
  204. {
  205. _gamePlayFile.groupMeshSkinAnimations();
  206. }
  207. std::string outputFilePath = arguments.getOutputFilePath();
  208. if (arguments.textOutputEnabled())
  209. {
  210. int pos = outputFilePath.find_last_of('.');
  211. if (pos > 2)
  212. {
  213. std::string path = outputFilePath.substr(0, pos);
  214. path.append(".xml");
  215. LOG(1, "Saving debug file: %s\n", path.c_str());
  216. if (!_gamePlayFile.saveText(path))
  217. {
  218. LOG(1, "Error writing text file: %s\n", path.c_str());
  219. }
  220. }
  221. }
  222. else
  223. {
  224. LOG(1, "Saving binary file: %s\n", outputFilePath.c_str());
  225. if (!_gamePlayFile.saveBinary(outputFilePath))
  226. {
  227. LOG(1, "Error writing binary file: %s\n", outputFilePath.c_str());
  228. }
  229. }
  230. }
  231. void FBXSceneEncoder::loadScene(FbxScene* fbxScene)
  232. {
  233. Scene* scene = new Scene();
  234. scene->setId(fbxScene->GetName());
  235. if (scene->getId().length() == 0)
  236. {
  237. scene->setId("__SCENE__");
  238. }
  239. // Load all of the nodes and their contents.
  240. FbxNode* rootNode = fbxScene->GetRootNode();
  241. if (rootNode)
  242. {
  243. print("Triangulate.");
  244. triangulateRecursive(rootNode);
  245. print("Load nodes.");
  246. // Don't include the FBX root node in the GPB.
  247. const int childCount = rootNode->GetChildCount();
  248. for (int i = 0; i < childCount; ++i)
  249. {
  250. Node* node = loadNode(rootNode->GetChild(i));
  251. if (node)
  252. {
  253. scene->add(node);
  254. }
  255. }
  256. }
  257. // Load the MeshSkin information from the scene's poses.
  258. loadBindShapes(fbxScene);
  259. // Find the ambient light of the scene
  260. FbxColor ambientColor = fbxScene->GetGlobalSettings().GetAmbientColor();
  261. scene->setAmbientColor((float)ambientColor.mRed, (float)ambientColor.mGreen, (float)ambientColor.mBlue);
  262. // Assign the first camera node (if there is one) in the scene as the active camera
  263. // This ensures that if there's a camera in the scene that it is assigned as the
  264. // active camera.
  265. // TODO: add logic to find the "active" camera node in the fbxScene
  266. scene->setActiveCameraNode(scene->getFirstCameraNode());
  267. _gamePlayFile.addScene(scene);
  268. }
  269. void FBXSceneEncoder::loadAnimationChannels(FbxAnimLayer* animLayer, FbxNode* fbxNode, Animation* animation)
  270. {
  271. const char* name = fbxNode->GetName();
  272. //Node* node = _gamePlayFile.getNode(name);
  273. // Determine which properties are animated on this node
  274. // Find the transform at each key frame
  275. // TODO: Ignore properties that are not animated (scale, rotation, translation)
  276. // This should result in only one animation channel per animated node.
  277. float startTime = FLT_MAX, stopTime = -1.0f, frameRate = -FLT_MAX;
  278. bool tx = false, ty = false, tz = false, rx = false, ry = false, rz = false, sx = false, sy = false, sz = false;
  279. FbxAnimCurve* animCurve = NULL;
  280. animCurve = getCurve(fbxNode->LclTranslation, animLayer, FBXSDK_CURVENODE_COMPONENT_X);
  281. if (animCurve)
  282. {
  283. tx = true;
  284. findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
  285. }
  286. animCurve = getCurve(fbxNode->LclTranslation, animLayer, FBXSDK_CURVENODE_COMPONENT_Y);
  287. if (animCurve)
  288. {
  289. ty = true;
  290. findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
  291. }
  292. animCurve = getCurve(fbxNode->LclTranslation, animLayer, FBXSDK_CURVENODE_COMPONENT_Z);
  293. if (animCurve)
  294. {
  295. tz = true;
  296. findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
  297. }
  298. animCurve = getCurve(fbxNode->LclRotation, animLayer, FBXSDK_CURVENODE_COMPONENT_X);
  299. if (animCurve)
  300. {
  301. rx = true;
  302. findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
  303. }
  304. animCurve = getCurve(fbxNode->LclRotation, animLayer, FBXSDK_CURVENODE_COMPONENT_Y);
  305. if (animCurve)
  306. {
  307. ry = true;
  308. findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
  309. }
  310. animCurve = getCurve(fbxNode->LclRotation, animLayer, FBXSDK_CURVENODE_COMPONENT_Z);
  311. if (animCurve)
  312. {
  313. rz = true;
  314. findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
  315. }
  316. animCurve = getCurve(fbxNode->LclScaling, animLayer, FBXSDK_CURVENODE_COMPONENT_X);
  317. if (animCurve)
  318. {
  319. sx = true;
  320. findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
  321. }
  322. animCurve = getCurve(fbxNode->LclScaling, animLayer, FBXSDK_CURVENODE_COMPONENT_Y);
  323. if (animCurve)
  324. {
  325. sy = true;
  326. findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
  327. }
  328. animCurve = getCurve(fbxNode->LclScaling, animLayer, FBXSDK_CURVENODE_COMPONENT_Z);
  329. if (animCurve)
  330. {
  331. sz = true;
  332. findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
  333. }
  334. if (!(sx || sy || sz || rx || ry || rz || tx || ty || tz))
  335. return; // no animation channels
  336. assert(startTime != FLT_MAX);
  337. assert(stopTime >= 0.0f);
  338. // Determine which animation channels to create
  339. std::vector<unsigned int> channelAttribs;
  340. if (sx && sy && sz)
  341. {
  342. if (rx || ry || rz)
  343. {
  344. if (tx && ty && tz)
  345. {
  346. channelAttribs.push_back(Transform::ANIMATE_SCALE_ROTATE_TRANSLATE);
  347. }
  348. else
  349. {
  350. channelAttribs.push_back(Transform::ANIMATE_SCALE_ROTATE);
  351. if (tx)
  352. channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_X);
  353. if (ty)
  354. channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Y);
  355. if (tz)
  356. channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Z);
  357. }
  358. }
  359. else
  360. {
  361. if (tx && ty && tz)
  362. {
  363. channelAttribs.push_back(Transform::ANIMATE_SCALE_TRANSLATE);
  364. }
  365. else
  366. {
  367. channelAttribs.push_back(Transform::ANIMATE_SCALE);
  368. if (tx)
  369. channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_X);
  370. if (ty)
  371. channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Y);
  372. if (tz)
  373. channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Z);
  374. }
  375. }
  376. }
  377. else
  378. {
  379. if (rx || ry || rz)
  380. {
  381. if (tx && ty && tz)
  382. {
  383. channelAttribs.push_back(Transform::ANIMATE_ROTATE_TRANSLATE);
  384. }
  385. else
  386. {
  387. channelAttribs.push_back(Transform::ANIMATE_ROTATE);
  388. if (tx)
  389. channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_X);
  390. if (ty)
  391. channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Y);
  392. if (tz)
  393. channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Z);
  394. }
  395. }
  396. else
  397. {
  398. if (tx && ty && tz)
  399. {
  400. channelAttribs.push_back(Transform::ANIMATE_TRANSLATE);
  401. }
  402. else
  403. {
  404. if (tx)
  405. channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_X);
  406. if (ty)
  407. channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Y);
  408. if (tz)
  409. channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Z);
  410. }
  411. }
  412. if (sx)
  413. channelAttribs.push_back(Transform::ANIMATE_SCALE_X);
  414. if (sy)
  415. channelAttribs.push_back(Transform::ANIMATE_SCALE_Y);
  416. if (sz)
  417. channelAttribs.push_back(Transform::ANIMATE_SCALE_Z);
  418. }
  419. unsigned int channelCount = channelAttribs.size();
  420. assert(channelCount > 0);
  421. // Allocate channel list
  422. int channelStart = animation->getAnimationChannelCount();
  423. for (unsigned int i = 0; i < channelCount; ++i)
  424. {
  425. AnimationChannel* channel = new AnimationChannel();
  426. channel->setTargetId(name);
  427. channel->setInterpolation(AnimationChannel::LINEAR);
  428. channel->setTargetAttribute(channelAttribs[i]);
  429. animation->add(channel);
  430. }
  431. // Evaulate animation curve in increments of frameRate and populate channel data.
  432. FbxAMatrix fbxMatrix;
  433. Matrix matrix;
  434. float increment = 1000.0f / frameRate;
  435. for (float time = startTime; time <= stopTime; time += increment)
  436. {
  437. // Clamp time to stopTime
  438. time = std::min(time, stopTime);
  439. // Evalulate the animation at this time
  440. FbxTime kTime;
  441. kTime.SetMilliSeconds((FbxLongLong)time);
  442. fbxMatrix = fbxNode->EvaluateLocalTransform(kTime);
  443. copyMatrix(fbxMatrix, matrix);
  444. // Decompose the evalulated transformation matrix into separate
  445. // scale, rotation and translation.
  446. Vector3 scale;
  447. Quaternion rotation;
  448. Vector3 translation;
  449. matrix.decompose(&scale, &rotation, &translation);
  450. rotation.normalize();
  451. // Append keyframe data to all channels
  452. for (unsigned int i = channelStart, channelEnd = channelStart + channelCount; i < channelEnd; ++i)
  453. {
  454. appendKeyFrame(fbxNode, animation->getAnimationChannel(i), time, scale, rotation, translation);
  455. }
  456. }
  457. if (_groupAnimation != animation)
  458. {
  459. // TODO explain
  460. _gamePlayFile.addAnimation(animation);
  461. }
  462. }
  463. void FBXSceneEncoder::loadAnimationLayer(FbxAnimLayer* fbxAnimLayer, FbxNode* fbxNode, const EncoderArguments& arguments)
  464. {
  465. bool animationGroupId = false;
  466. const char* name = fbxNode->GetName();
  467. // Check if this node's animations are supposed to be grouped
  468. if (name && arguments.containsGroupNodeId(name))
  469. {
  470. animationGroupId = true;
  471. _groupAnimation = new Animation();
  472. _groupAnimation->setId(arguments.getAnimationId(name));
  473. }
  474. Animation* animation = _groupAnimation;
  475. if (!animation)
  476. {
  477. animation = new Animation();
  478. animation->setId(name);
  479. }
  480. loadAnimationChannels(fbxAnimLayer, fbxNode, animation);
  481. const int childCount = fbxNode->GetChildCount();
  482. for (int modelCount = 0; modelCount < childCount; ++modelCount)
  483. {
  484. loadAnimationLayer(fbxAnimLayer, fbxNode->GetChild(modelCount), arguments);
  485. }
  486. if (animationGroupId)
  487. {
  488. _gamePlayFile.addAnimation(_groupAnimation);
  489. _groupAnimation = NULL;
  490. }
  491. }
  492. void FBXSceneEncoder::loadAnimations(FbxScene* fbxScene, const EncoderArguments& arguments)
  493. {
  494. FbxAnimEvaluator* evaluator = fbxScene->GetEvaluator();
  495. if (!evaluator)
  496. return;
  497. FbxAnimStack* animStack = evaluator->GetContext();
  498. if (!animStack)
  499. return;
  500. for (int i = 0; i < fbxScene->GetSrcObjectCount(FBX_TYPE(FbxAnimStack)); ++i)
  501. {
  502. FbxAnimStack* animStack = FbxCast<FbxAnimStack>(fbxScene->GetSrcObject(FBX_TYPE(FbxAnimStack), i));
  503. int nbAnimLayers = animStack->GetMemberCount(FBX_TYPE(FbxAnimLayer));
  504. for (int l = 0; l < nbAnimLayers; ++l)
  505. {
  506. FbxAnimLayer* animLayer = animStack->GetMember(FBX_TYPE(FbxAnimLayer), l);
  507. loadAnimationLayer(animLayer, fbxScene->GetRootNode(), arguments);
  508. }
  509. }
  510. }
  511. Node* FBXSceneEncoder::loadNode(FbxNode* fbxNode)
  512. {
  513. Node* node = NULL;
  514. // Check if this node has already been loaded
  515. const char* id = fbxNode->GetName();
  516. if (id && strlen(id) > 0)
  517. {
  518. node = _gamePlayFile.getNode(fbxNode->GetName());
  519. if (node)
  520. {
  521. return node;
  522. }
  523. }
  524. node = new Node();
  525. if (id)
  526. {
  527. node->setId(id);
  528. }
  529. _gamePlayFile.addNode(node);
  530. transformNode(fbxNode, node);
  531. loadCamera(fbxNode, node);
  532. loadLight(fbxNode, node);
  533. loadModel(fbxNode, node);
  534. if (fbxNode->GetSkeleton())
  535. {
  536. // Indicate that this is a joint node for the purpose of debugging.
  537. // The XML debug output will print that this node is a joint.
  538. node->setIsJoint(true);
  539. }
  540. // Load child nodes
  541. const int childCount = fbxNode->GetChildCount();
  542. for (int i = 0; i < childCount; ++i)
  543. {
  544. Node* child = loadNode(fbxNode->GetChild(i));
  545. if (child)
  546. {
  547. node->addChild(child);
  548. }
  549. }
  550. return node;
  551. }
  552. Mesh* FBXSceneEncoder::getMesh(FbxUInt64 meshId)
  553. {
  554. // Check if this mesh was already loaded.
  555. std::map<FbxUInt64, Mesh*>::iterator it = _meshes.find(meshId);
  556. if (it != _meshes.end())
  557. {
  558. return it->second;
  559. }
  560. return NULL;
  561. }
  562. void FBXSceneEncoder::saveMesh(FbxUInt64 meshId, Mesh* mesh)
  563. {
  564. assert(mesh);
  565. if (!getMesh(meshId))
  566. {
  567. _meshes[meshId] = mesh;
  568. }
  569. }
  570. void FBXSceneEncoder::print(const char* str)
  571. {
  572. LOG(1, "%s\n", str);
  573. }
  574. void FBXSceneEncoder::transformNode(FbxNode* fbxNode, Node* node)
  575. {
  576. FbxAMatrix matrix;
  577. if (fbxNode->GetCamera() || fbxNode->GetLight())
  578. {
  579. // TODO: Why is this necessary for Camera and Light?
  580. matrix.SetTRS(fbxNode->LclTranslation.Get(), fbxNode->LclRotation.Get(), fbxNode->LclScaling.Get());
  581. }
  582. else
  583. {
  584. matrix = fbxNode->EvaluateLocalTransform();
  585. }
  586. float m[16];
  587. copyMatrix(matrix, m);
  588. node->setTransformMatrix(m);
  589. }
  590. void FBXSceneEncoder::loadBindShapes(FbxScene* fbxScene)
  591. {
  592. float m[16];
  593. const int poseCount = fbxScene->GetPoseCount();
  594. for (int i = 0; i < poseCount; ++i)
  595. {
  596. FbxPose* pose = fbxScene->GetPose(i);
  597. assert(pose);
  598. if (pose->IsBindPose() && pose->GetCount() > 0)
  599. {
  600. FbxNode* fbxNode = pose->GetNode(0);
  601. if (fbxNode->GetMesh() != NULL)
  602. {
  603. Node* node = _gamePlayFile.getNode(fbxNode->GetName());
  604. assert(node && node->getModel());
  605. Model* model = node->getModel();
  606. if (model && model->getSkin())
  607. {
  608. MeshSkin* skin = model->getSkin();
  609. copyMatrix(pose->GetMatrix(0), m);
  610. skin->setBindShape(m);
  611. }
  612. }
  613. }
  614. }
  615. }
  616. void FBXSceneEncoder::loadCamera(FbxNode* fbxNode, Node* node)
  617. {
  618. FbxCamera* fbxCamera = fbxNode->GetCamera();
  619. if (!fbxCamera)
  620. {
  621. return;
  622. }
  623. Camera* camera = new Camera();
  624. const char* name = fbxNode->GetName();
  625. if (name)
  626. {
  627. std::string id(name);
  628. id.append("_Camera");
  629. camera->setId(id);
  630. }
  631. camera->setAspectRatio(getAspectRatio(fbxCamera));
  632. camera->setNearPlane((float)fbxCamera->NearPlane.Get());
  633. camera->setFarPlane((float)fbxCamera->FarPlane.Get());
  634. if (fbxCamera->ProjectionType.Get() == FbxCamera::eOrthogonal)
  635. {
  636. camera->setOrthographic();
  637. camera->setViewportWidth((float)fbxCamera->GetApertureWidth());
  638. camera->setViewportWidth((float)fbxCamera->GetApertureHeight());
  639. // xmag in FBX can be calculated from: OrthoZoom * 30.0 / 2.0
  640. camera->setViewportWidth((float)fbxCamera->OrthoZoom.Get() * 15.0f);
  641. }
  642. else if (fbxCamera->ProjectionType.Get() == FbxCamera::ePerspective)
  643. {
  644. camera->setPerspective();
  645. camera->setFieldOfView(getFieldOfView(fbxCamera));
  646. }
  647. else
  648. {
  649. LOG(2, "Warning: Unknown camera type in node.\n");
  650. return;
  651. }
  652. _gamePlayFile.addCamera(camera);
  653. node->setCamera(camera);
  654. }
  655. void FBXSceneEncoder::loadLight(FbxNode* fbxNode, Node* node)
  656. {
  657. FbxLight* fbxLight = fbxNode->GetLight();
  658. if (!fbxLight)
  659. {
  660. return;
  661. }
  662. Light* light = new Light();
  663. const char* name = fbxNode->GetName();
  664. if (name)
  665. {
  666. std::string id(name);
  667. id.append("_Light");
  668. light->setId(id);
  669. }
  670. FbxDouble3 color = fbxLight->Color.Get();
  671. light->setColor((float)color[0], (float)color[1], (float)color[2]);
  672. switch (fbxLight->LightType.Get())
  673. {
  674. case FbxLight::ePoint:
  675. {
  676. FbxLight::EDecayType decayType = fbxLight->DecayType.Get();
  677. switch (decayType)
  678. {
  679. case FbxLight::eNone:
  680. // No decay. Can assume we have an ambient light, because ambient lights in the scene are
  681. // converted to point lights with no decay when exporting to FBX.
  682. light->setAmbientLight();
  683. break;
  684. case FbxLight::eLinear:
  685. light->setPointLight();
  686. light->setLinearAttenuation((float)fbxLight->DecayStart.Get());
  687. break;
  688. case FbxLight::eQuadratic:
  689. light->setPointLight();
  690. light->setQuadraticAttenuation((float)fbxLight->DecayStart.Get());
  691. break;
  692. case FbxLight::eCubic:
  693. default:
  694. // Not supported..
  695. break;
  696. }
  697. break;
  698. }
  699. case FbxLight::eDirectional:
  700. {
  701. light->setDirectionalLight();
  702. break;
  703. }
  704. case FbxLight::eSpot:
  705. {
  706. light->setSpotLight();
  707. FbxLight::EDecayType decayType = fbxLight->DecayType.Get();
  708. switch (decayType)
  709. {
  710. case FbxLight::eNone:
  711. // No decay.
  712. break;
  713. case FbxLight::eLinear:
  714. light->setLinearAttenuation((float)fbxLight->DecayStart.Get());
  715. break;
  716. case FbxLight::eQuadratic:
  717. light->setQuadraticAttenuation((float)fbxLight->DecayStart.Get());
  718. break;
  719. case FbxLight::eCubic:
  720. // Not supported..
  721. break;
  722. }
  723. light->setFalloffAngle(MATH_DEG_TO_RAD((float)fbxLight->OuterAngle.Get())); // fall off angle
  724. break;
  725. }
  726. default:
  727. {
  728. LOG(2, "Warning: Unknown light type in node.\n");
  729. return;
  730. }
  731. }
  732. _gamePlayFile.addLight(light);
  733. node->setLight(light);
  734. }
  735. void FBXSceneEncoder::loadModel(FbxNode* fbxNode, Node* node)
  736. {
  737. FbxMesh* fbxMesh = fbxNode->GetMesh();
  738. if (!fbxMesh)
  739. {
  740. return;
  741. }
  742. if (fbxMesh->IsTriangleMesh())
  743. {
  744. Mesh* mesh = loadMesh(fbxMesh);
  745. Model* model = new Model();
  746. model->setMesh(mesh);
  747. node->setModel(model);
  748. loadSkin(fbxMesh, model);
  749. if (model->getSkin())
  750. {
  751. // TODO: explain
  752. node->resetTransformMatrix();
  753. }
  754. }
  755. }
  756. void FBXSceneEncoder::loadSkin(FbxMesh* fbxMesh, Model* model)
  757. {
  758. const int deformerCount = fbxMesh->GetDeformerCount();
  759. for (int i = 0; i < deformerCount; ++i)
  760. {
  761. FbxDeformer* deformer = fbxMesh->GetDeformer(i);
  762. if (deformer->GetDeformerType() == FbxDeformer::eSkin)
  763. {
  764. FbxSkin* fbxSkin = static_cast<FbxSkin*>(deformer);
  765. MeshSkin* skin = new MeshSkin();
  766. std::vector<std::string> jointNames;
  767. std::vector<Node*> joints;
  768. std::vector<Matrix> bindPoses;
  769. const int clusterCount = fbxSkin->GetClusterCount();
  770. for (int j = 0; j < clusterCount; ++j)
  771. {
  772. FbxCluster* cluster = fbxSkin->GetCluster(j);
  773. assert(cluster);
  774. FbxNode* linkedNode = cluster->GetLink();
  775. if (linkedNode && linkedNode->GetSkeleton())
  776. {
  777. const char* jointName = linkedNode->GetName();
  778. assert(jointName);
  779. jointNames.push_back(jointName);
  780. Node* joint = loadNode(linkedNode);
  781. assert(joint);
  782. joints.push_back(joint);
  783. FbxAMatrix matrix;
  784. cluster->GetTransformLinkMatrix(matrix);
  785. Matrix m;
  786. copyMatrix(matrix.Inverse(), m);
  787. bindPoses.push_back(m);
  788. }
  789. }
  790. skin->setJointNames(jointNames);
  791. skin->setJoints(joints);
  792. skin->setBindPoses(bindPoses);
  793. model->setSkin(skin);
  794. break;
  795. }
  796. }
  797. }
  798. Mesh* FBXSceneEncoder::loadMesh(FbxMesh* fbxMesh)
  799. {
  800. // Check if this mesh has already been loaded.
  801. Mesh* mesh = getMesh(fbxMesh->GetUniqueID());
  802. if (mesh)
  803. {
  804. return mesh;
  805. }
  806. mesh = new Mesh();
  807. // GamePlay requires that a mesh have a unique ID but FbxMesh doesn't have a string ID.
  808. const char* name = fbxMesh->GetNode()->GetName();
  809. if (name)
  810. {
  811. std::string id(name);
  812. id.append("_Mesh");
  813. mesh->setId(id);
  814. }
  815. // The number of mesh parts is equal to the number of materials that affect this mesh.
  816. // There is always at least one mesh part.
  817. std::vector<MeshPart*> meshParts;
  818. const int materialCount = fbxMesh->GetNode()->GetMaterialCount();
  819. int meshPartSize = (materialCount > 0) ? materialCount : 1;
  820. for (int i = 0; i < meshPartSize; ++i)
  821. {
  822. meshParts.push_back(new MeshPart());
  823. }
  824. // Find the blend weights and blend indices if this mesh is skinned.
  825. std::vector<std::vector<Vector2> > weights;
  826. bool hasSkin = loadBlendWeights(fbxMesh, weights);
  827. // Get list of uv sets for mesh
  828. FbxStringList uvSetNameList;
  829. fbxMesh->GetUVSetNames(uvSetNameList);
  830. const int uvSetCount = uvSetNameList.GetCount();
  831. int vertexIndex = 0;
  832. FbxVector4* controlPoints = fbxMesh->GetControlPoints();
  833. const int polygonCount = fbxMesh->GetPolygonCount();
  834. for (int polyIndex = 0; polyIndex < polygonCount; ++polyIndex)
  835. {
  836. const int polygonSize = fbxMesh->GetPolygonSize(polyIndex);
  837. for (int posInPoly = 0; posInPoly < polygonSize; ++posInPoly)
  838. {
  839. int controlPointIndex = fbxMesh->GetPolygonVertex(polyIndex, posInPoly);
  840. Vertex vertex;
  841. FbxVector4& position = controlPoints[controlPointIndex];
  842. vertex.position.x = (float)position[0];
  843. vertex.position.y = (float)position[1];
  844. vertex.position.z = (float)position[2];
  845. // Load tex coords for all uv sets
  846. for (int uvSetIndex = 0; uvSetIndex < uvSetCount; ++uvSetIndex)
  847. {
  848. const FbxGeometryElementUV* uvElement = fbxMesh->GetElementUV(uvSetNameList.GetStringAt(uvSetIndex));
  849. if (uvElement)
  850. loadTextureCoords(fbxMesh, uvElement, uvSetIndex, polyIndex, posInPoly, vertexIndex, &vertex);
  851. }
  852. // Load other data
  853. loadNormal(fbxMesh, vertexIndex, controlPointIndex, &vertex);
  854. loadTangent(fbxMesh, vertexIndex, controlPointIndex, &vertex);
  855. loadBinormal(fbxMesh, vertexIndex, controlPointIndex, &vertex);
  856. loadVertexColor(fbxMesh, vertexIndex, controlPointIndex, &vertex);
  857. if (hasSkin)
  858. {
  859. loadBlendData(weights[controlPointIndex], &vertex);
  860. }
  861. // Determine which mesh part this vertex index should be added to based on the material that affects it.
  862. int meshPartIndex = 0;
  863. const int elementMatrialCount = fbxMesh->GetElementMaterialCount();
  864. for (int k = 0; k < elementMatrialCount; ++k)
  865. {
  866. FbxGeometryElementMaterial* elementMaterial = fbxMesh->GetElementMaterial(k);
  867. meshPartIndex = elementMaterial->GetIndexArray().GetAt(polyIndex);
  868. }
  869. // Add the vertex to the mesh if it hasn't already been added and find the vertex index.
  870. unsigned int index;
  871. if (mesh->contains(vertex))
  872. {
  873. index = mesh->getVertexIndex(vertex);
  874. }
  875. else
  876. {
  877. index = mesh->addVertex(vertex);
  878. }
  879. meshParts[meshPartIndex]->addIndex(index);
  880. vertexIndex++;
  881. }
  882. }
  883. const size_t meshpartsSize = meshParts.size();
  884. for (size_t i = 0; i < meshpartsSize; ++i)
  885. {
  886. mesh->addMeshPart(meshParts[i]);
  887. }
  888. // The order that the vertex elements are add to the list matters.
  889. // It should be the same order as how the Vertex data is written.
  890. // Position
  891. mesh->addVetexAttribute(POSITION, Vertex::POSITION_COUNT);
  892. const Vertex& vertex = mesh->vertices[0];
  893. // Normals
  894. if (vertex.hasNormal)
  895. {
  896. mesh->addVetexAttribute(NORMAL, Vertex::NORMAL_COUNT);
  897. }
  898. // Tangents
  899. if (vertex.hasTangent)
  900. {
  901. mesh->addVetexAttribute(TANGENT, Vertex::TANGENT_COUNT);
  902. }
  903. // Binormals
  904. if (vertex.hasBinormal)
  905. {
  906. mesh->addVetexAttribute(BINORMAL, Vertex::BINORMAL_COUNT);
  907. }
  908. // Texture Coordinates
  909. for (unsigned int i = 0; i < MAX_UV_SETS; ++i)
  910. {
  911. if (vertex.hasTexCoord[i])
  912. {
  913. mesh->addVetexAttribute(TEXCOORD0 + i, Vertex::TEXCOORD_COUNT);
  914. }
  915. }
  916. // Diffuse Color
  917. if (vertex.hasDiffuse)
  918. {
  919. mesh->addVetexAttribute(COLOR, Vertex::DIFFUSE_COUNT);
  920. }
  921. // Skinning BlendWeights BlendIndices
  922. if (vertex.hasWeights)
  923. {
  924. mesh->addVetexAttribute(BLENDWEIGHTS, Vertex::BLEND_WEIGHTS_COUNT);
  925. mesh->addVetexAttribute(BLENDINDICES, Vertex::BLEND_INDICES_COUNT);
  926. }
  927. _gamePlayFile.addMesh(mesh);
  928. saveMesh(fbxMesh->GetUniqueID(), mesh);
  929. return mesh;
  930. }
  931. void FBXSceneEncoder::triangulateRecursive(FbxNode* fbxNode)
  932. {
  933. // Triangulate all NURBS, patch and mesh under this node recursively.
  934. FbxNodeAttribute* nodeAttribute = fbxNode->GetNodeAttribute();
  935. if (nodeAttribute)
  936. {
  937. if (nodeAttribute->GetAttributeType() == FbxNodeAttribute::eMesh ||
  938. nodeAttribute->GetAttributeType() == FbxNodeAttribute::eNurbs ||
  939. nodeAttribute->GetAttributeType() == FbxNodeAttribute::eNurbsSurface ||
  940. nodeAttribute->GetAttributeType() == FbxNodeAttribute::ePatch)
  941. {
  942. FbxGeometryConverter converter(fbxNode->GetFbxManager());
  943. converter.TriangulateInPlace(fbxNode);
  944. }
  945. }
  946. const int childCount = fbxNode->GetChildCount();
  947. for (int childIndex = 0; childIndex < childCount; ++childIndex)
  948. {
  949. triangulateRecursive(fbxNode->GetChild(childIndex));
  950. }
  951. }
  952. ////////////////////////////////////
  953. // Functions
  954. ////////////////////////////////////
  955. float getAspectRatio(FbxCamera* fbxCamera)
  956. {
  957. return (float)fbxCamera->FilmAspectRatio.Get();
  958. /*
  959. FbxCamera::ECameraAspectRatioMode camAspectRatioMode = fbxCamera->GetAspectRatioMode();
  960. double aspectX = fbxCamera->AspectWidth.Get();
  961. double aspectY = fbxCamera->AspectHeight.Get();
  962. double aspectRatio = 1.333333;
  963. switch ( camAspectRatioMode)
  964. {
  965. case FbxCamera::eWINDOW_SIZE:
  966. aspectRatio = aspectX / aspectY;
  967. break;
  968. case FbxCamera::eFIXED_RATIO:
  969. aspectRatio = aspectX;
  970. break;
  971. case FbxCamera::eFIXED_RESOLUTION:
  972. aspectRatio = aspectX / aspectY * fbxCamera->GetPixelRatio();
  973. break;
  974. case FbxCamera::eFIXED_WIDTH:
  975. aspectRatio = fbxCamera->GetPixelRatio() / aspectY;
  976. break;
  977. case FbxCamera::eFIXED_HEIGHT:
  978. aspectRatio = fbxCamera->GetPixelRatio() * aspectX;
  979. break;
  980. default:
  981. break;
  982. }
  983. return (float)aspectRatio;
  984. */
  985. }
  986. inline double vfov(double hfov, double aspect)
  987. {
  988. static const double MATH_PI_180 = 0.01745329251994329576923690768489;
  989. static const double MATH_180_PI = 57.295779513082320876798154814105;
  990. return (2.0 * atan((aspect) * tan( (hfov * MATH_PI_180) * 0.5)) * MATH_180_PI);
  991. }
  992. float getFieldOfView(FbxCamera* fbxCamera)
  993. {
  994. double fieldOfViewX = 0.0;
  995. double fieldOfViewY = 0.0;
  996. double filmHeight = fbxCamera->GetApertureHeight();
  997. double filmWidth = fbxCamera->GetApertureWidth() * fbxCamera->GetSqueezeRatio();
  998. double apertureRatio = filmHeight / filmWidth;
  999. if ( fbxCamera->GetApertureMode() == FbxCamera::eVertical)
  1000. {
  1001. fieldOfViewY = fbxCamera->FieldOfView.Get();
  1002. }
  1003. else if (fbxCamera->GetApertureMode() == FbxCamera::eHorizontal)
  1004. {
  1005. fieldOfViewX = fbxCamera->FieldOfView.Get();
  1006. fieldOfViewY = vfov( fieldOfViewX, apertureRatio);
  1007. }
  1008. else if (fbxCamera->GetApertureMode() == FbxCamera::eFocalLength)
  1009. {
  1010. fieldOfViewX = fbxCamera->ComputeFieldOfView(fbxCamera->FocalLength.Get());
  1011. fieldOfViewY = vfov( fieldOfViewX, apertureRatio);
  1012. }
  1013. else if (fbxCamera->GetApertureMode() == FbxCamera::eHorizAndVert)
  1014. {
  1015. fieldOfViewY = fbxCamera->FieldOfViewY.Get();
  1016. }
  1017. else
  1018. {
  1019. fieldOfViewY = 45.0;
  1020. }
  1021. return (float)fieldOfViewY;
  1022. }
  1023. void loadTextureCoords(FbxMesh* fbxMesh, const FbxGeometryElementUV* uvs, int uvSetIndex, int polyIndex, int posInPoly, int meshVertexIndex, Vertex* vertex)
  1024. {
  1025. assert(fbxMesh && polyIndex >=0 && posInPoly >= 0);
  1026. const bool useIndex = uvs->GetReferenceMode() != FbxGeometryElement::eDirect;
  1027. const int indexCount = useIndex ? uvs->GetIndexArray().GetCount() : 0;
  1028. int uvIndex = -1;
  1029. switch (uvs->GetMappingMode())
  1030. {
  1031. case FbxGeometryElement::eByControlPoint:
  1032. {
  1033. // Get the index of the current vertex in control points array
  1034. int polyVertIndex = fbxMesh->GetPolygonVertex(polyIndex, posInPoly);
  1035. // The UV index depends on the reference mode
  1036. uvIndex = useIndex ? uvs->GetIndexArray().GetAt(polyVertIndex) : polyVertIndex;
  1037. }
  1038. break;
  1039. case FbxGeometryElement::eByPolygonVertex:
  1040. if (meshVertexIndex < indexCount)
  1041. {
  1042. uvIndex = useIndex ? uvs->GetIndexArray().GetAt(meshVertexIndex) : meshVertexIndex;
  1043. }
  1044. break;
  1045. default:
  1046. // Only support eByPolygonVertex and eByControlPoint mappings
  1047. break;
  1048. }
  1049. vertex->hasTexCoord[uvSetIndex] = true;
  1050. // Store UV information in vertex
  1051. if (uvIndex != -1)
  1052. {
  1053. FbxVector2 uvValue = uvs->GetDirectArray().GetAt(uvIndex);
  1054. vertex->texCoord[uvSetIndex].x = (float)uvValue[0];
  1055. vertex->texCoord[uvSetIndex].y = (float)uvValue[1];
  1056. }
  1057. }
  1058. void loadNormal(FbxMesh* fbxMesh, int vertexIndex, int controlPointIndex, Vertex* vertex)
  1059. {
  1060. if (fbxMesh->GetElementNormalCount() > 0)
  1061. {
  1062. // Get only the first
  1063. FbxGeometryElementNormal* normal = fbxMesh->GetElementNormal(0);
  1064. FbxGeometryElement::EMappingMode mappingMode = normal->GetMappingMode();
  1065. if (mappingMode == FbxGeometryElement::eByControlPoint)
  1066. {
  1067. switch (normal->GetReferenceMode())
  1068. {
  1069. case FbxGeometryElement::eDirect:
  1070. {
  1071. FbxVector4 vec4 = normal->GetDirectArray().GetAt(controlPointIndex);
  1072. vertex->hasNormal = true;
  1073. vertex->normal.x = (float)vec4[0];
  1074. vertex->normal.y = (float)vec4[1];
  1075. vertex->normal.z = (float)vec4[2];
  1076. }
  1077. break;
  1078. case FbxGeometryElement::eIndexToDirect:
  1079. {
  1080. int id = normal->GetIndexArray().GetAt(controlPointIndex);
  1081. FbxVector4 vec4 = normal->GetDirectArray().GetAt(id);
  1082. vertex->hasNormal = true;
  1083. vertex->normal.x = (float)vec4[0];
  1084. vertex->normal.y = (float)vec4[1];
  1085. vertex->normal.z = (float)vec4[2];
  1086. }
  1087. break;
  1088. default:
  1089. break;
  1090. }
  1091. }
  1092. else if (mappingMode == FbxGeometryElement::eByPolygonVertex)
  1093. {
  1094. switch (normal->GetReferenceMode())
  1095. {
  1096. case FbxGeometryElement::eDirect:
  1097. {
  1098. FbxVector4 vec4 = normal->GetDirectArray().GetAt(vertexIndex);
  1099. vertex->hasNormal = true;
  1100. vertex->normal.x = (float)vec4[0];
  1101. vertex->normal.y = (float)vec4[1];
  1102. vertex->normal.z = (float)vec4[2];
  1103. }
  1104. break;
  1105. case FbxGeometryElement::eIndexToDirect:
  1106. {
  1107. int id = normal->GetIndexArray().GetAt(vertexIndex);
  1108. FbxVector4 vec4 = normal->GetDirectArray().GetAt(id);
  1109. vertex->hasNormal = true;
  1110. vertex->normal.x = (float)vec4[0];
  1111. vertex->normal.y = (float)vec4[1];
  1112. vertex->normal.z = (float)vec4[2];
  1113. }
  1114. break;
  1115. default:
  1116. break;
  1117. }
  1118. }
  1119. }
  1120. }
  1121. void loadTangent(FbxMesh* fbxMesh, int vertexIndex, int controlPointIndex, Vertex* vertex)
  1122. {
  1123. if (fbxMesh->GetElementTangentCount() > 0)
  1124. {
  1125. // Get only the first tangent
  1126. FbxGeometryElementTangent* tangent = fbxMesh->GetElementTangent(0);
  1127. FbxGeometryElement::EMappingMode mappingMode = tangent->GetMappingMode();
  1128. if (mappingMode == FbxGeometryElement::eByControlPoint)
  1129. {
  1130. switch (tangent->GetReferenceMode())
  1131. {
  1132. case FbxGeometryElement::eDirect:
  1133. {
  1134. FbxVector4 vec4 = tangent->GetDirectArray().GetAt(controlPointIndex);
  1135. vertex->hasTangent = true;
  1136. vertex->tangent.x = (float)vec4[0];
  1137. vertex->tangent.y = (float)vec4[1];
  1138. vertex->tangent.z = (float)vec4[2];
  1139. }
  1140. break;
  1141. case FbxGeometryElement::eIndexToDirect:
  1142. {
  1143. int id = tangent->GetIndexArray().GetAt(controlPointIndex);
  1144. FbxVector4 vec4 = tangent->GetDirectArray().GetAt(id);
  1145. vertex->hasTangent = true;
  1146. vertex->tangent.x = (float)vec4[0];
  1147. vertex->tangent.y = (float)vec4[1];
  1148. vertex->tangent.z = (float)vec4[2];
  1149. }
  1150. break;
  1151. default:
  1152. break;
  1153. }
  1154. }
  1155. else if (mappingMode == FbxGeometryElement::eByPolygonVertex)
  1156. {
  1157. switch (tangent->GetReferenceMode())
  1158. {
  1159. case FbxGeometryElement::eDirect:
  1160. {
  1161. FbxVector4 vec4 = tangent->GetDirectArray().GetAt(vertexIndex);
  1162. vertex->hasTangent = true;
  1163. vertex->tangent.x = (float)vec4[0];
  1164. vertex->tangent.y = (float)vec4[1];
  1165. vertex->tangent.z = (float)vec4[2];
  1166. }
  1167. break;
  1168. case FbxGeometryElement::eIndexToDirect:
  1169. {
  1170. int id = tangent->GetIndexArray().GetAt(vertexIndex);
  1171. FbxVector4 vec4 = tangent->GetDirectArray().GetAt(id);
  1172. vertex->hasTangent = true;
  1173. vertex->tangent.x = (float)vec4[0];
  1174. vertex->tangent.y = (float)vec4[1];
  1175. vertex->tangent.z = (float)vec4[2];
  1176. }
  1177. break;
  1178. default:
  1179. break;
  1180. }
  1181. }
  1182. }
  1183. }
  1184. void loadBinormal(FbxMesh* fbxMesh, int vertexIndex, int controlPointIndex, Vertex* vertex)
  1185. {
  1186. if (fbxMesh->GetElementBinormalCount() > 0)
  1187. {
  1188. // Get only the first binormal.
  1189. FbxGeometryElementBinormal* binormal = fbxMesh->GetElementBinormal(0);
  1190. FbxGeometryElement::EMappingMode mappingMode = binormal->GetMappingMode();
  1191. if (mappingMode == FbxGeometryElement::eByControlPoint)
  1192. {
  1193. switch (binormal->GetReferenceMode())
  1194. {
  1195. case FbxGeometryElement::eDirect:
  1196. {
  1197. FbxVector4 vec4 = binormal->GetDirectArray().GetAt(controlPointIndex);
  1198. vertex->hasBinormal = true;
  1199. vertex->binormal.x = (float)vec4[0];
  1200. vertex->binormal.y = (float)vec4[1];
  1201. vertex->binormal.z = (float)vec4[2];
  1202. }
  1203. break;
  1204. case FbxGeometryElement::eIndexToDirect:
  1205. {
  1206. int id = binormal->GetIndexArray().GetAt(controlPointIndex);
  1207. FbxVector4 vec4 = binormal->GetDirectArray().GetAt(id);
  1208. vertex->hasBinormal = true;
  1209. vertex->binormal.x = (float)vec4[0];
  1210. vertex->binormal.y = (float)vec4[1];
  1211. vertex->binormal.z = (float)vec4[2];
  1212. }
  1213. break;
  1214. default:
  1215. break;
  1216. }
  1217. }
  1218. else if (mappingMode == FbxGeometryElement::eByPolygonVertex)
  1219. {
  1220. switch (binormal->GetReferenceMode())
  1221. {
  1222. case FbxGeometryElement::eDirect:
  1223. {
  1224. FbxVector4 vec4 = binormal->GetDirectArray().GetAt(vertexIndex);
  1225. vertex->hasBinormal = true;
  1226. vertex->binormal.x = (float)vec4[0];
  1227. vertex->binormal.y = (float)vec4[1];
  1228. vertex->binormal.z = (float)vec4[2];
  1229. }
  1230. break;
  1231. case FbxGeometryElement::eIndexToDirect:
  1232. {
  1233. int id = binormal->GetIndexArray().GetAt(vertexIndex);
  1234. FbxVector4 vec4 = binormal->GetDirectArray().GetAt(id);
  1235. vertex->hasBinormal = true;
  1236. vertex->binormal.x = (float)vec4[0];
  1237. vertex->binormal.y = (float)vec4[1];
  1238. vertex->binormal.z = (float)vec4[2];
  1239. }
  1240. break;
  1241. default:
  1242. break;
  1243. }
  1244. }
  1245. }
  1246. }
  1247. void loadVertexColor(FbxMesh* fbxMesh, int vertexIndex, int controlPointIndex, Vertex* vertex)
  1248. {
  1249. if (fbxMesh->GetElementVertexColorCount() > 0)
  1250. {
  1251. // Get only the first vertex color.
  1252. FbxGeometryElementVertexColor* vertexColor = fbxMesh->GetElementVertexColor(0);
  1253. FbxGeometryElement::EMappingMode mappingMode = vertexColor->GetMappingMode();
  1254. if (mappingMode == FbxGeometryElement::eByControlPoint)
  1255. {
  1256. switch (vertexColor->GetReferenceMode())
  1257. {
  1258. case FbxGeometryElement::eDirect:
  1259. {
  1260. FbxColor color = vertexColor->GetDirectArray().GetAt(controlPointIndex);
  1261. vertex->hasDiffuse = true;
  1262. vertex->diffuse.x = (float)color.mRed;
  1263. vertex->diffuse.y = (float)color.mGreen;
  1264. vertex->diffuse.z = (float)color.mBlue;
  1265. vertex->diffuse.w = (float)color.mAlpha;
  1266. }
  1267. break;
  1268. case FbxGeometryElement::eIndexToDirect:
  1269. {
  1270. int id = vertexColor->GetIndexArray().GetAt(controlPointIndex);
  1271. FbxColor color = vertexColor->GetDirectArray().GetAt(id);
  1272. vertex->hasDiffuse = true;
  1273. vertex->diffuse.x = (float)color.mRed;
  1274. vertex->diffuse.y = (float)color.mGreen;
  1275. vertex->diffuse.z = (float)color.mBlue;
  1276. vertex->diffuse.w = (float)color.mAlpha;
  1277. }
  1278. break;
  1279. default:
  1280. break;
  1281. }
  1282. }
  1283. else if (mappingMode == FbxGeometryElement::eByPolygonVertex)
  1284. {
  1285. switch (vertexColor->GetReferenceMode())
  1286. {
  1287. case FbxGeometryElement::eDirect:
  1288. {
  1289. FbxColor color = vertexColor->GetDirectArray().GetAt(vertexIndex);
  1290. vertex->hasDiffuse = true;
  1291. vertex->diffuse.x = (float)color.mRed;
  1292. vertex->diffuse.y = (float)color.mGreen;
  1293. vertex->diffuse.z = (float)color.mBlue;
  1294. vertex->diffuse.w = (float)color.mAlpha;
  1295. }
  1296. break;
  1297. case FbxGeometryElement::eIndexToDirect:
  1298. {
  1299. int id = vertexColor->GetIndexArray().GetAt(vertexIndex);
  1300. FbxColor color = vertexColor->GetDirectArray().GetAt(id);
  1301. vertex->hasDiffuse = true;
  1302. vertex->diffuse.x = (float)color.mRed;
  1303. vertex->diffuse.y = (float)color.mGreen;
  1304. vertex->diffuse.z = (float)color.mBlue;
  1305. vertex->diffuse.w = (float)color.mAlpha;
  1306. }
  1307. break;
  1308. default:
  1309. break;
  1310. }
  1311. }
  1312. }
  1313. }
  1314. void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex)
  1315. {
  1316. size_t size = vertexWeights.size();
  1317. if (size >= 1)
  1318. {
  1319. vertex->hasWeights= true;
  1320. vertex->blendIndices.x = vertexWeights[0].x;
  1321. vertex->blendWeights.x = vertexWeights[0].y;
  1322. }
  1323. if (size >= 2)
  1324. {
  1325. vertex->blendIndices.y = vertexWeights[1].x;
  1326. vertex->blendWeights.y = vertexWeights[1].y;
  1327. }
  1328. if (size >= 3)
  1329. {
  1330. vertex->blendIndices.z = vertexWeights[2].x;
  1331. vertex->blendWeights.z = vertexWeights[2].y;
  1332. }
  1333. if (size >= 4)
  1334. {
  1335. vertex->blendIndices.w = vertexWeights[3].x;
  1336. vertex->blendWeights.w = vertexWeights[3].y;
  1337. }
  1338. //vertex->normalizeBlendWeight();
  1339. }
  1340. bool loadBlendWeights(FbxMesh* fbxMesh, std::vector<std::vector<Vector2> >& weights)
  1341. {
  1342. assert(fbxMesh);
  1343. const int vertexCount = fbxMesh->GetControlPointsCount();
  1344. FbxSkin* fbxSkin = NULL;
  1345. const int deformerCount = fbxMesh->GetDeformerCount();
  1346. for (int i = 0; i < deformerCount; ++i)
  1347. {
  1348. FbxDeformer* deformer = fbxMesh->GetDeformer(i);
  1349. if (deformer->GetDeformerType() == FbxDeformer::eSkin)
  1350. {
  1351. fbxSkin = static_cast<FbxSkin*>(deformer);
  1352. weights.resize(vertexCount);
  1353. const int clusterCount = fbxSkin->GetClusterCount();
  1354. for (int j = 0; j < clusterCount; ++j)
  1355. {
  1356. FbxCluster* cluster = fbxSkin->GetCluster(j);
  1357. assert(cluster);
  1358. const int vertexIndexCount = cluster->GetControlPointIndicesCount();
  1359. for (int k = 0; k < vertexIndexCount; ++k)
  1360. {
  1361. int index = cluster->GetControlPointIndices()[k];
  1362. if (index >= vertexCount)
  1363. {
  1364. continue;
  1365. }
  1366. double weight = cluster->GetControlPointWeights()[k];
  1367. if (weight == 0.0)
  1368. {
  1369. continue;
  1370. }
  1371. weights[index].push_back(Vector2((float)j, (float)weight));
  1372. }
  1373. }
  1374. // Only the first skin deformer will be loaded.
  1375. // There probably won't be more than one.
  1376. break;
  1377. }
  1378. }
  1379. return fbxSkin != NULL;
  1380. }
  1381. void findMinMaxTime(FbxAnimCurve* animCurve, float* startTime, float* stopTime, float* frameRate)
  1382. {
  1383. FbxTime start, stop;
  1384. FbxTimeSpan timeSpan;
  1385. animCurve->GetTimeInterval(timeSpan);
  1386. start = timeSpan.GetStart();
  1387. stop = timeSpan.GetStop();
  1388. *startTime = std::min(*startTime, (float)start.GetMilliSeconds());
  1389. *stopTime = std::max(*stopTime, (float)stop.GetMilliSeconds());
  1390. *frameRate = std::max(*frameRate, (float)stop.GetFrameRate(FbxTime::eDefaultMode));
  1391. }
  1392. void appendKeyFrame(FbxNode* fbxNode, AnimationChannel* channel, float time, const Vector3& scale, const Quaternion& rotation, const Vector3& translation)
  1393. {
  1394. // Write key time
  1395. channel->getKeyTimes().push_back(time);
  1396. // Write key values
  1397. std::vector<float>& keyValues = channel->getKeyValues();
  1398. switch (channel->getTargetAttribute())
  1399. {
  1400. case Transform::ANIMATE_SCALE:
  1401. {
  1402. keyValues.push_back(scale.x);
  1403. keyValues.push_back(scale.y);
  1404. keyValues.push_back(scale.z);
  1405. }
  1406. break;
  1407. case Transform::ANIMATE_SCALE_X:
  1408. {
  1409. keyValues.push_back(scale.x);
  1410. }
  1411. break;
  1412. case Transform::ANIMATE_SCALE_Y:
  1413. {
  1414. keyValues.push_back(scale.y);
  1415. }
  1416. break;
  1417. case Transform::ANIMATE_SCALE_Z:
  1418. {
  1419. keyValues.push_back(scale.z);
  1420. }
  1421. break;
  1422. case Transform::ANIMATE_ROTATE:
  1423. {
  1424. keyValues.push_back(rotation.x);
  1425. keyValues.push_back(rotation.y);
  1426. keyValues.push_back(rotation.z);
  1427. keyValues.push_back(rotation.w);
  1428. }
  1429. break;
  1430. case Transform::ANIMATE_TRANSLATE:
  1431. {
  1432. keyValues.push_back(translation.x);
  1433. keyValues.push_back(translation.y);
  1434. keyValues.push_back(translation.z);
  1435. }
  1436. break;
  1437. case Transform::ANIMATE_TRANSLATE_X:
  1438. {
  1439. keyValues.push_back(translation.x);
  1440. }
  1441. break;
  1442. case Transform::ANIMATE_TRANSLATE_Y:
  1443. {
  1444. keyValues.push_back(translation.y);
  1445. }
  1446. break;
  1447. case Transform::ANIMATE_TRANSLATE_Z:
  1448. {
  1449. keyValues.push_back(translation.z);
  1450. }
  1451. break;
  1452. case Transform::ANIMATE_ROTATE_TRANSLATE:
  1453. {
  1454. keyValues.push_back(rotation.x);
  1455. keyValues.push_back(rotation.y);
  1456. keyValues.push_back(rotation.z);
  1457. keyValues.push_back(rotation.w);
  1458. keyValues.push_back(translation.x);
  1459. keyValues.push_back(translation.y);
  1460. keyValues.push_back(translation.z);
  1461. }
  1462. break;
  1463. case Transform::ANIMATE_SCALE_ROTATE_TRANSLATE:
  1464. {
  1465. keyValues.push_back(scale.x);
  1466. keyValues.push_back(scale.y);
  1467. keyValues.push_back(scale.z);
  1468. keyValues.push_back(rotation.x);
  1469. keyValues.push_back(rotation.y);
  1470. keyValues.push_back(rotation.z);
  1471. keyValues.push_back(rotation.w);
  1472. keyValues.push_back(translation.x);
  1473. keyValues.push_back(translation.y);
  1474. keyValues.push_back(translation.z);
  1475. }
  1476. break;
  1477. case Transform::ANIMATE_SCALE_TRANSLATE:
  1478. {
  1479. keyValues.push_back(scale.x);
  1480. keyValues.push_back(scale.y);
  1481. keyValues.push_back(scale.z);
  1482. keyValues.push_back(translation.x);
  1483. keyValues.push_back(translation.y);
  1484. keyValues.push_back(translation.z);
  1485. }
  1486. break;
  1487. case Transform::ANIMATE_SCALE_ROTATE:
  1488. {
  1489. keyValues.push_back(scale.x);
  1490. keyValues.push_back(scale.y);
  1491. keyValues.push_back(scale.z);
  1492. keyValues.push_back(rotation.x);
  1493. keyValues.push_back(rotation.y);
  1494. keyValues.push_back(rotation.z);
  1495. keyValues.push_back(rotation.w);
  1496. }
  1497. break;
  1498. default:
  1499. {
  1500. LOG(1, "Warning: Invalid animatoin target (%d) attribute for node: %s.\n", channel->getTargetAttribute(), fbxNode->GetName());
  1501. }
  1502. return;
  1503. }
  1504. }
  1505. void decompose(FbxNode* fbxNode, float time, Vector3* scale, Quaternion* rotation, Vector3* translation)
  1506. {
  1507. FbxAMatrix fbxMatrix;
  1508. Matrix matrix;
  1509. FbxTime kTime;
  1510. kTime.SetMilliSeconds((FbxLongLong)time);
  1511. fbxMatrix = fbxNode->EvaluateLocalTransform(kTime);
  1512. copyMatrix(fbxMatrix, matrix);
  1513. matrix.decompose(scale, rotation, translation);
  1514. }
  1515. AnimationChannel* createAnimationChannel(FbxNode* fbxNode, unsigned int targetAttrib, const std::vector<float>& keyTimes, const std::vector<float>& keyValues)
  1516. {
  1517. AnimationChannel* channel = new AnimationChannel();
  1518. channel->setTargetId(fbxNode->GetName());
  1519. channel->setKeyTimes(keyTimes);
  1520. channel->setKeyValues(keyValues);
  1521. channel->setInterpolation(AnimationChannel::LINEAR);
  1522. channel->setTargetAttribute(targetAttrib);
  1523. return channel;
  1524. }
  1525. void addScaleChannel(Animation* animation, FbxNode* fbxNode, float startTime, float stopTime)
  1526. {
  1527. std::vector<float> keyTimes;
  1528. std::vector<float> keyValues;
  1529. Vector3 scale;
  1530. Quaternion rotation;
  1531. Vector3 translation;
  1532. decompose(fbxNode, startTime, &scale, &rotation, &translation);
  1533. keyTimes.push_back(startTime);
  1534. keyValues.push_back(scale.x);
  1535. keyValues.push_back(scale.y);
  1536. keyValues.push_back(scale.z);
  1537. decompose(fbxNode, stopTime, &scale, &rotation, &translation);
  1538. keyTimes.push_back(stopTime);
  1539. keyValues.push_back(scale.x);
  1540. keyValues.push_back(scale.y);
  1541. keyValues.push_back(scale.z);
  1542. AnimationChannel* channel = createAnimationChannel(fbxNode, Transform::ANIMATE_SCALE, keyTimes, keyValues);
  1543. animation->add(channel);
  1544. }
  1545. void addTranslateChannel(Animation* animation, FbxNode* fbxNode, float startTime, float stopTime)
  1546. {
  1547. std::vector<float> keyTimes;
  1548. std::vector<float> keyValues;
  1549. Vector3 scale;
  1550. Quaternion rotation;
  1551. Vector3 translation;
  1552. decompose(fbxNode, startTime, &scale, &rotation, &translation);
  1553. keyTimes.push_back(startTime);
  1554. keyValues.push_back(translation.x);
  1555. keyValues.push_back(translation.y);
  1556. keyValues.push_back(translation.z);
  1557. decompose(fbxNode, stopTime, &scale, &rotation, &translation);
  1558. keyTimes.push_back(stopTime);
  1559. keyValues.push_back(translation.x);
  1560. keyValues.push_back(translation.y);
  1561. keyValues.push_back(translation.z);
  1562. AnimationChannel* channel = createAnimationChannel(fbxNode, Transform::ANIMATE_TRANSLATE, keyTimes, keyValues);
  1563. animation->add(channel);
  1564. }
  1565. void copyMatrix(const FbxMatrix& fbxMatrix, float* matrix)
  1566. {
  1567. int i = 0;
  1568. for (int row = 0; row < 4; ++row)
  1569. {
  1570. for (int col = 0; col < 4; ++col)
  1571. {
  1572. matrix[i++] = (float)fbxMatrix.Get(row, col);
  1573. }
  1574. }
  1575. }
  1576. void copyMatrix(const FbxMatrix& fbxMatrix, Matrix& matrix)
  1577. {
  1578. int i = 0;
  1579. for (int row = 0; row < 4; ++row)
  1580. {
  1581. for (int col = 0; col < 4; ++col)
  1582. {
  1583. matrix.m[i++] = (float)fbxMatrix.Get(row, col);
  1584. }
  1585. }
  1586. }
  1587. bool isGroupAnimationPossible(FbxScene* fbxScene)
  1588. {
  1589. FbxNode* rootNode = fbxScene->GetRootNode();
  1590. if (rootNode)
  1591. {
  1592. if (isGroupAnimationPossible(rootNode))
  1593. return true;
  1594. }
  1595. return false;
  1596. }
  1597. bool isGroupAnimationPossible(FbxNode* fbxNode)
  1598. {
  1599. if (fbxNode)
  1600. {
  1601. FbxMesh* fbxMesh = fbxNode->GetMesh();
  1602. if (isGroupAnimationPossible(fbxMesh))
  1603. return true;
  1604. const int childCount = fbxNode->GetChildCount();
  1605. for (int i = 0; i < childCount; ++i)
  1606. {
  1607. if (isGroupAnimationPossible(fbxNode->GetChild(i)))
  1608. return true;
  1609. }
  1610. }
  1611. return false;
  1612. }
  1613. bool isGroupAnimationPossible(FbxMesh* fbxMesh)
  1614. {
  1615. if (fbxMesh)
  1616. {
  1617. const int deformerCount = fbxMesh->GetDeformerCount();
  1618. for (int i = 0; i < deformerCount; ++i)
  1619. {
  1620. FbxDeformer* deformer = fbxMesh->GetDeformer(i);
  1621. if (deformer->GetDeformerType() == FbxDeformer::eSkin)
  1622. {
  1623. FbxSkin* fbxSkin = static_cast<FbxSkin*>(deformer);
  1624. if (fbxSkin)
  1625. {
  1626. return true;
  1627. }
  1628. }
  1629. }
  1630. }
  1631. return false;
  1632. }
  1633. #endif