AssetImporter.cpp 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Exception.h"
  24. #include "Animation.h"
  25. #include "File.h"
  26. #include "Geometry.h"
  27. #include "IndexBuffer.h"
  28. #include "Material.h"
  29. #include "Model.h"
  30. #include "Octree.h"
  31. #include "PhysicsWorld.h"
  32. #include "Quaternion.h"
  33. #include "Scene.h"
  34. #include "StaticModel.h"
  35. #include "StringUtils.h"
  36. #include "Vector3.h"
  37. #include "VertexBuffer.h"
  38. #include "XMLFile.h"
  39. #include <algorithm>
  40. #include <cstring>
  41. #include <iostream>
  42. #include <map>
  43. #include <set>
  44. #include <assimp.hpp>
  45. #include <aiScene.h>
  46. #include <aiPostProcess.h>
  47. #include "DebugNew.h"
  48. struct ExportModel
  49. {
  50. ExportModel() :
  51. mTotalVertices(0),
  52. mTotalIndices(0),
  53. mRootBone(0)
  54. {
  55. }
  56. std::string mOutName;
  57. const aiScene* mScene;
  58. aiNode* mRootNode;
  59. std::set<unsigned> mMeshIndices;
  60. std::vector<aiMesh*> mMeshes;
  61. std::vector<aiNode*> mMeshNodes;
  62. std::vector<aiNode*> mBones;
  63. std::vector<aiAnimation*> mAnimations;
  64. std::vector<float> mBoneRadii;
  65. std::vector<BoundingBox> mBoneHitboxes;
  66. aiNode* mRootBone;
  67. unsigned mTotalVertices;
  68. unsigned mTotalIndices;
  69. };
  70. struct ExportScene
  71. {
  72. std::string mOutName;
  73. std::string mResourcePath;
  74. bool mLocalIDs;
  75. bool mNoExtensions;
  76. bool mSaveBinary;
  77. const aiScene* mScene;
  78. aiNode* mRootNode;
  79. std::vector<ExportModel> mModels;
  80. std::vector<aiNode*> mNodes;
  81. std::vector<unsigned> mNodeModelIndices;
  82. };
  83. int main(int argc, char** argv);
  84. void run(const std::vector<std::string>& arguments);
  85. void dumpNodes(const aiScene* scene, aiNode* rootNode, unsigned level);
  86. void exportModel(const aiScene* scene, aiNode* rootNode, const std::string& outName, bool noAnimations);
  87. void collectMeshes(ExportModel& model, aiNode* node);
  88. void collectBones(ExportModel& model);
  89. void collectBonesFinal(std::vector<aiNode*>& dest, const std::set<aiNode*>& necessary, aiNode* node);
  90. void collectAnimations(ExportModel& model);
  91. void buildBoneCollisionInfo(ExportModel& model);
  92. void buildAndSaveModel(ExportModel& model);
  93. void buildAndSaveAnimations(ExportModel& model);
  94. void exportScene(const aiScene* scene, aiNode* rootNode, const std::string& outName, const std::string& resourcePath, bool localIDs,
  95. bool noExtensions, bool saveBinary);
  96. void collectSceneModels(ExportScene& scene, aiNode* node);
  97. void collectSceneNodes(ExportScene& scene, aiNode* node);
  98. void buildAndSaveScene(ExportScene& scene);
  99. void exportMaterials(const aiScene* scene, const std::string& outName, const std::string& resourcePath);
  100. void buildAndSaveMaterial(aiMaterial* material, const std::string& outName, const std::string& resourcePath);
  101. std::set<unsigned> getMeshesUnderNodeSet(aiNode* node);
  102. std::vector<std::pair<aiNode*, aiMesh*> > getMeshesUnderNode(const aiScene* scene, aiNode* node);
  103. unsigned getMeshIndex(const aiScene* scene, aiMesh* mesh);
  104. unsigned getBoneIndex(ExportModel& model, const std::string& boneName);
  105. aiBone* getMeshBone(ExportModel& model, const std::string& boneName);
  106. Matrix4x3 getOffsetMatrix(ExportModel& model, const std::string& boneName, bool useMeshTransform);
  107. void getBlendData(ExportModel& model, aiMesh* mesh, std::vector<unsigned>& boneMappings, std::vector<std::vector<unsigned char> >&
  108. blendIndices, std::vector<std::vector<float> >& blendWeights);
  109. void writeShortIndices(unsigned short*& dest, aiMesh* mesh, unsigned index, unsigned offset);
  110. void writeLargeIndices(unsigned*& dest, aiMesh* mesh, unsigned index, unsigned offset);
  111. void writeVertex(float*& dest, aiMesh* mesh, unsigned index, unsigned elementMask, BoundingBox& box,
  112. const Matrix4x3& vertexTransform, const Matrix3& normalTransform, std::vector<std::vector<unsigned char> >& blendIndices,
  113. std::vector<std::vector<float> >& blendWeights);
  114. unsigned getElementMask(aiMesh* mesh);
  115. aiNode* findNode(const std::string& name, aiNode* rootNode, bool caseSensitive = true);
  116. std::string toStdString(const aiString& str);
  117. Vector3 toVector3(const aiVector3D& vec);
  118. Vector2 toVector2(const aiVector2D& vec);
  119. Quaternion toQuaternion(const aiQuaternion& quat);
  120. aiMatrix4x4 getDerivedTransform(aiNode* node, aiNode* rootNode);
  121. aiMatrix4x4 getDerivedTransform(aiMatrix4x4 transform, aiNode* node, aiNode* rootNode);
  122. void getPosRotScale(const aiMatrix4x4& transform, Vector3& pos, Quaternion& rot, Vector3& scale);
  123. void errorExit(const std::string& error);
  124. int main(int argc, char** argv)
  125. {
  126. std::vector<std::string> arguments;
  127. for (int i = 1; i < argc; ++i)
  128. arguments.push_back(replace(std::string(argv[i]), '/', '\\'));
  129. try
  130. {
  131. run(arguments);
  132. }
  133. catch (Exception& e)
  134. {
  135. std::cout << e.whatStr() << std::endl;
  136. return 1;
  137. }
  138. return 0;
  139. }
  140. void run(const std::vector<std::string>& arguments)
  141. {
  142. if (arguments.size() < 2)
  143. {
  144. errorExit(
  145. "Usage: AssetImporter <command> <input file> <output file> [options]\n"
  146. "See http://assimp.sourceforge.net/main_features_formats.html for input formats\n\n"
  147. "Commands:\n"
  148. "model Export a model and animations\n"
  149. "scene Export a scene and its models\n"
  150. "dumpnodes Dump scene node structure. No output file is generated\n"
  151. "\n"
  152. "Options:\n"
  153. "-b Save scene in binary format (default: XML)\n"
  154. "-l Use local ID's for scene entities\n"
  155. "-na Do not export animations\n"
  156. "-ne Do not create Octree & PhysicsWorld extensions to the scene\n"
  157. "-nm Do not export materials\n"
  158. "-pX Use base path X for resources in the scene file\n"
  159. "-rX Use scene node X as root node\n"
  160. "-t Generate tangents to model(s)"
  161. );
  162. }
  163. std::string command = toLower(arguments[0]);
  164. std::string inFile = arguments[1];
  165. std::string outFile;
  166. std::string rootNodeName;
  167. std::string resourcePath;
  168. if (arguments.size() > 2)
  169. outFile = arguments[2];
  170. bool noMaterials = false;
  171. bool noAnimations = false;
  172. bool noExtensions = false;
  173. bool localIDs = false;
  174. bool saveBinary = false;
  175. unsigned flags =
  176. aiProcess_ConvertToLeftHanded |
  177. aiProcess_JoinIdenticalVertices |
  178. aiProcess_Triangulate |
  179. aiProcess_GenSmoothNormals |
  180. aiProcess_LimitBoneWeights |
  181. aiProcess_ImproveCacheLocality |
  182. aiProcess_FixInfacingNormals |
  183. aiProcess_FindInvalidData |
  184. aiProcess_FindInstances |
  185. aiProcess_OptimizeMeshes;
  186. for (unsigned i = 3; i < arguments.size(); ++i)
  187. {
  188. if ((arguments[i].length() >= 2) && (arguments[i][0] == '-'))
  189. {
  190. std::string parameter;
  191. if (arguments[i].length() >= 3)
  192. parameter = arguments[i].substr(2);
  193. switch (tolower(arguments[i][1]))
  194. {
  195. case 'b':
  196. saveBinary = true;
  197. break;
  198. case 'l':
  199. localIDs = true;
  200. break;
  201. case 'p':
  202. resourcePath = parameter;
  203. break;
  204. case 'r':
  205. rootNodeName = parameter;
  206. break;
  207. case 't':
  208. flags |= aiProcess_CalcTangentSpace;
  209. break;
  210. case 'n':
  211. if (!parameter.empty())
  212. {
  213. switch (tolower(parameter[0]))
  214. {
  215. case 'a':
  216. noAnimations = true;
  217. break;
  218. case 'e':
  219. noExtensions = true;
  220. break;
  221. case 'm':
  222. noMaterials = true;
  223. break;
  224. }
  225. }
  226. break;
  227. }
  228. }
  229. }
  230. if ((command != "model") && (command != "scene") && (command != "dumpnodes"))
  231. errorExit("Unrecognized command " + command);
  232. Assimp::Importer importer;
  233. std::cout << "Reading file " << inFile << std::endl;
  234. const aiScene* scene = importer.ReadFile(inFile.c_str(), flags);
  235. if (!scene)
  236. errorExit("Could not open or parse input file " + inFile);
  237. aiNode* rootNode = scene->mRootNode;
  238. if (!rootNodeName.empty())
  239. {
  240. rootNode = findNode(rootNodeName, scene->mRootNode, false);
  241. if (!rootNode)
  242. errorExit("Could not find scene node " + rootNodeName);
  243. }
  244. if (!resourcePath.empty())
  245. resourcePath = fixPath(resourcePath);
  246. if (command == "model")
  247. exportModel(scene, rootNode, outFile, noAnimations);
  248. if (command == "scene")
  249. exportScene(scene, rootNode, outFile, resourcePath, localIDs, noExtensions, saveBinary);
  250. if ((!noMaterials) && ((command == "model") || (command == "scene")))
  251. exportMaterials(scene, outFile, resourcePath);
  252. if (command == "dumpnodes")
  253. dumpNodes(scene, rootNode, 0);
  254. }
  255. void dumpNodes(const aiScene* scene, aiNode* rootNode, unsigned level)
  256. {
  257. if (!rootNode)
  258. return;
  259. std::string indent;
  260. indent.resize(level * 2);
  261. for (unsigned i = 0; i < level * 2; ++i)
  262. indent[i] = ' ';
  263. Vector3 pos, scale;
  264. Quaternion rot;
  265. aiMatrix4x4 transform = getDerivedTransform(rootNode, 0);
  266. getPosRotScale(transform, pos, rot, scale);
  267. std::cout << indent << "Node " << toStdString(rootNode->mName) << " pos " << toString(pos) << std::endl;
  268. if (rootNode->mNumMeshes == 1)
  269. std::cout << indent << " " << rootNode->mNumMeshes << " geometry" << std::endl;
  270. if (rootNode->mNumMeshes > 1)
  271. std::cout << indent << " " << rootNode->mNumMeshes << " geometries" << std::endl;
  272. for (unsigned i = 0; i < rootNode->mNumChildren; ++i)
  273. dumpNodes(scene, rootNode->mChildren[i], level + 1);
  274. }
  275. void exportModel(const aiScene* scene, aiNode* rootNode, const std::string& outName, bool noAnimations)
  276. {
  277. if (outName.empty())
  278. errorExit("No output file defined");
  279. ExportModel model;
  280. model.mScene = scene;
  281. model.mRootNode = rootNode;
  282. model.mOutName = outName;
  283. collectMeshes(model, model.mRootNode);
  284. collectBones(model);
  285. buildBoneCollisionInfo(model);
  286. buildAndSaveModel(model);
  287. if (!noAnimations)
  288. {
  289. collectAnimations(model);
  290. buildAndSaveAnimations(model);
  291. }
  292. }
  293. void collectMeshes(ExportModel& model, aiNode* node)
  294. {
  295. for (unsigned i = 0; i < node->mNumMeshes; ++i)
  296. {
  297. aiMesh* mesh = model.mScene->mMeshes[node->mMeshes[i]];
  298. for (unsigned j = 0; j < model.mMeshes.size(); ++j)
  299. {
  300. if (mesh == model.mMeshes[j])
  301. {
  302. std::cout << "Warning: same mesh found multiple times" << std::endl;
  303. break;
  304. }
  305. }
  306. model.mMeshIndices.insert(node->mMeshes[i]);
  307. model.mMeshes.push_back(mesh);
  308. model.mMeshNodes.push_back(node);
  309. model.mTotalVertices += mesh->mNumVertices;
  310. model.mTotalIndices += mesh->mNumFaces * 3;
  311. }
  312. for (unsigned i = 0; i < node->mNumChildren; ++i)
  313. collectMeshes(model, node->mChildren[i]);
  314. }
  315. void collectBones(ExportModel& model)
  316. {
  317. std::set<aiNode*> necessary;
  318. std::set<aiNode*> rootNodes;
  319. for (unsigned i = 0; i < model.mMeshes.size(); ++i)
  320. {
  321. aiMesh* mesh = model.mMeshes[i];
  322. aiNode* meshNode = model.mMeshNodes[i];
  323. aiNode* meshParentNode = meshNode->mParent;
  324. aiNode* rootNode = 0;
  325. for (unsigned j = 0; j < mesh->mNumBones; ++j)
  326. {
  327. aiBone* bone = mesh->mBones[j];
  328. std::string boneName(toStdString(bone->mName));
  329. aiNode* boneNode = findNode(boneName, model.mScene->mRootNode, true);
  330. if (!boneNode)
  331. errorExit("Could not find scene node for bone " + boneName);
  332. necessary.insert(boneNode);
  333. rootNode = boneNode;
  334. for (;;)
  335. {
  336. boneNode = boneNode->mParent;
  337. if ((!boneNode) || (boneNode == meshNode) || (boneNode == meshParentNode))
  338. break;
  339. rootNode = boneNode;
  340. necessary.insert(boneNode);
  341. }
  342. if (rootNodes.find(rootNode) == rootNodes.end())
  343. rootNodes.insert(rootNode);
  344. }
  345. }
  346. // If we find multiple root nodes, try to remedy by using their parent instead
  347. if (rootNodes.size() > 1)
  348. {
  349. aiNode* commonParent = (*rootNodes.begin())->mParent;
  350. for (std::set<aiNode*>::iterator i = rootNodes.begin(); i != rootNodes.end(); ++i)
  351. {
  352. if ((*i) != commonParent)
  353. {
  354. if ((!commonParent) || ((*i)->mParent != commonParent))
  355. errorExit("Skeleton with multiple root nodes found, not supported");
  356. }
  357. }
  358. rootNodes.clear();
  359. rootNodes.insert(commonParent);
  360. necessary.insert(commonParent);
  361. }
  362. model.mRootBone = *rootNodes.begin();
  363. collectBonesFinal(model.mBones, necessary, model.mRootBone);
  364. // Initialize the bone collision info
  365. model.mBoneRadii.resize(model.mBones.size());
  366. model.mBoneHitboxes.resize(model.mBones.size());
  367. for (unsigned i = 0; i < model.mBones.size(); ++i)
  368. {
  369. model.mBoneRadii[i] = 0.0f;
  370. model.mBoneHitboxes[i] = BoundingBox(0.0f, 0.0f);
  371. }
  372. }
  373. void collectBonesFinal(std::vector<aiNode*>& dest, const std::set<aiNode*>& necessary, aiNode* node)
  374. {
  375. if (necessary.find(node) != necessary.end())
  376. {
  377. dest.push_back(node);
  378. for (unsigned i = 0; i < node->mNumChildren; ++i)
  379. collectBonesFinal(dest, necessary, node->mChildren[i]);
  380. }
  381. }
  382. void collectAnimations(ExportModel& model)
  383. {
  384. const aiScene* scene = model.mScene;
  385. for (unsigned i = 0; i < scene->mNumAnimations; ++i)
  386. {
  387. aiAnimation* anim = scene->mAnimations[i];
  388. bool modelBoneFound = false;
  389. for (unsigned j = 0; j < anim->mNumChannels; ++j)
  390. {
  391. aiNodeAnim* channel = anim->mChannels[j];
  392. std::string channelName = toStdString(channel->mNodeName);
  393. if (getBoneIndex(model, channelName) != M_MAX_UNSIGNED)
  394. {
  395. modelBoneFound = true;
  396. break;
  397. }
  398. }
  399. if (modelBoneFound)
  400. model.mAnimations.push_back(anim);
  401. }
  402. }
  403. void buildBoneCollisionInfo(ExportModel& model)
  404. {
  405. for (unsigned i = 0; i < model.mMeshes.size(); ++i)
  406. {
  407. aiMesh* mesh = model.mMeshes[i];
  408. aiMatrix4x4 meshWorldTransform = getDerivedTransform(model.mMeshNodes[i], 0);
  409. for (unsigned j = 0; j < mesh->mNumBones; ++j)
  410. {
  411. aiBone* bone = mesh->mBones[j];
  412. std::string boneName = toStdString(bone->mName);
  413. unsigned boneIndex = getBoneIndex(model, boneName);
  414. if (boneIndex == M_MAX_UNSIGNED)
  415. continue;
  416. aiNode* boneNode = model.mBones[boneIndex];
  417. aiMatrix4x4 boneWorldTransform = getDerivedTransform(boneNode, 0);
  418. aiMatrix4x4 boneInverse = boneWorldTransform;
  419. boneInverse.Inverse();
  420. for (unsigned k = 0; k < bone->mNumWeights; ++k)
  421. {
  422. float weight = bone->mWeights[k].mWeight;
  423. if (weight > 0.33f)
  424. {
  425. aiVector3D vertexBoneSpace = bone->mOffsetMatrix * mesh->mVertices[bone->mWeights[k].mVertexId];
  426. Vector3 vertex = toVector3(vertexBoneSpace);
  427. float radius = vertex.getLength();
  428. if (radius > model.mBoneRadii[boneIndex])
  429. model.mBoneRadii[boneIndex] = radius;
  430. model.mBoneHitboxes[boneIndex].merge(vertex);
  431. }
  432. }
  433. }
  434. }
  435. }
  436. void buildAndSaveModel(ExportModel& model)
  437. {
  438. if (!model.mRootNode)
  439. errorExit("Null root node for model");
  440. std::string rootNodeName = toStdString(model.mRootNode->mName);
  441. if (!model.mMeshes.size())
  442. errorExit("No geometries found starting from node " + rootNodeName);
  443. std::cout << "Writing model " << rootNodeName << std::endl;
  444. if (model.mBones.size())
  445. {
  446. std::cout << "Model has a skeleton with " << model.mBones.size() << " bones, rootbone " +
  447. toStdString(model.mRootBone->mName) << std::endl;
  448. }
  449. SharedPtr<Model> outModel(new Model(0));
  450. outModel->setNumGeometries(model.mMeshes.size());
  451. std::vector<std::vector<unsigned> > allBoneMappings;
  452. BoundingBox box;
  453. bool combineBuffers = true;
  454. // Check if buffers can be combined (same vertex element mask, under 65535 vertices)
  455. unsigned elementMask = getElementMask(model.mMeshes[0]);
  456. for (unsigned i = 1; i < model.mMeshes.size(); ++i)
  457. {
  458. if (getElementMask(model.mMeshes[i]) != elementMask)
  459. {
  460. combineBuffers = false;
  461. break;
  462. }
  463. }
  464. // Check if keeping separate buffers allows to avoid 32-bit indices
  465. if ((combineBuffers) && (model.mTotalVertices > 65535))
  466. {
  467. bool allUnder65k = true;
  468. for (unsigned i = 0; i < model.mMeshes.size(); ++i)
  469. {
  470. if (model.mMeshes[i]->mNumVertices > 65535)
  471. allUnder65k = false;
  472. }
  473. if (allUnder65k == true)
  474. combineBuffers = false;
  475. }
  476. if (!combineBuffers)
  477. {
  478. std::cout << "Using separate buffers" << std::endl;
  479. for (unsigned i = 0; i < model.mMeshes.size(); ++i)
  480. {
  481. // Get the world transform of the mesh for baking into the vertices
  482. Vector3 pos, scale;
  483. Quaternion rot;
  484. getPosRotScale(getDerivedTransform(model.mMeshNodes[i], model.mRootNode), pos, rot, scale);
  485. Matrix4x3 vertexTransform;
  486. Matrix3 normalTransform;
  487. vertexTransform.define(pos, rot, scale);
  488. normalTransform = rot.getRotationMatrix();
  489. SharedPtr<IndexBuffer> ib(new IndexBuffer(0));
  490. SharedPtr<VertexBuffer> vb(new VertexBuffer(0));
  491. SharedPtr<Geometry> geom(new Geometry());
  492. aiMesh* mesh = model.mMeshes[i];
  493. std::cout << "Geometry " << i << " has " << mesh->mNumVertices << " vertices " << mesh->mNumFaces * 3 << " indices"
  494. << std::endl;
  495. bool largeIndices = mesh->mNumVertices > 65535;
  496. unsigned elementMask = getElementMask(mesh);
  497. ib->setSize(mesh->mNumFaces * 3, largeIndices);
  498. vb->setSize(mesh->mNumVertices, elementMask);
  499. // Build the index data
  500. void* indexData = ib->lock(0, ib->getIndexCount(), LOCK_NORMAL);
  501. if (!largeIndices)
  502. {
  503. unsigned short* dest = (unsigned short*)indexData;
  504. for (unsigned j = 0; j < mesh->mNumFaces; ++j)
  505. writeShortIndices(dest, mesh, j, 0);
  506. }
  507. else
  508. {
  509. unsigned* dest = (unsigned*)indexData;
  510. for (unsigned j = 0; j < mesh->mNumFaces; ++j)
  511. writeLargeIndices(dest, mesh, j, 0);
  512. }
  513. // Build the vertex data
  514. // If there are bones, get blend data
  515. std::vector<std::vector<unsigned char> > blendIndices;
  516. std::vector<std::vector<float> > blendWeights;
  517. std::vector<unsigned> boneMappings;
  518. if (model.mBones.size())
  519. getBlendData(model, mesh, boneMappings, blendIndices, blendWeights);
  520. void* vertexData = vb->lock(0, vb->getVertexCount(), LOCK_NORMAL);
  521. float* dest = (float*)vertexData;
  522. for (unsigned j = 0; j < mesh->mNumVertices; ++j)
  523. writeVertex(dest, mesh, j, elementMask, box, vertexTransform, normalTransform, blendIndices, blendWeights);
  524. ib->unlock();
  525. vb->unlock();
  526. // Define the geometry
  527. geom->setIndexBuffer(ib);
  528. geom->setVertexBuffer(0, vb);
  529. geom->setDrawRange(TRIANGLE_LIST, 0, mesh->mNumFaces * 3, true);
  530. outModel->setNumGeometryLodLevels(i, 1);
  531. outModel->setGeometry(i, 0, geom);
  532. if (model.mBones.size() > MAX_SKIN_MATRICES)
  533. allBoneMappings.push_back(boneMappings);
  534. }
  535. }
  536. else
  537. {
  538. std::cout << "Using combined buffers" << std::endl;
  539. SharedPtr<IndexBuffer> ib(new IndexBuffer(0));
  540. SharedPtr<VertexBuffer> vb(new VertexBuffer(0));
  541. bool largeIndices = model.mTotalIndices > 65535;
  542. ib->setSize(model.mTotalIndices, largeIndices);
  543. vb->setSize(model.mTotalVertices, elementMask);
  544. unsigned startVertexOffset = 0;
  545. unsigned startIndexOffset = 0;
  546. void* indexData = ib->lock(0, ib->getIndexCount(), LOCK_NORMAL);
  547. void* vertexData = vb->lock(0, vb->getVertexCount(), LOCK_NORMAL);
  548. // The buffer is in CPU memory, and therefore locking is irrelevant. Unlock so that draw range checking can lock again
  549. ib->unlock();
  550. vb->unlock();
  551. for (unsigned i = 0; i < model.mMeshes.size(); ++i)
  552. {
  553. // Get the world transform of the mesh for baking into the vertices
  554. Vector3 pos, scale;
  555. Quaternion rot;
  556. getPosRotScale(getDerivedTransform(model.mMeshNodes[i], model.mRootNode), pos, rot, scale);
  557. Matrix4x3 vertexTransform;
  558. Matrix3 normalTransform;
  559. vertexTransform.define(pos, rot, scale);
  560. normalTransform = rot.getRotationMatrix();
  561. SharedPtr<Geometry> geom(new Geometry());
  562. aiMesh* mesh = model.mMeshes[i];
  563. std::cout << "Geometry " << i << " has " << mesh->mNumVertices << " vertices " << mesh->mNumFaces * 3 << " indices"
  564. << std::endl;
  565. // Build the index data
  566. if (!largeIndices)
  567. {
  568. unsigned short* dest = (unsigned short*)indexData + startIndexOffset;
  569. for (unsigned j = 0; j < mesh->mNumFaces; ++j)
  570. writeShortIndices(dest, mesh, j, startVertexOffset);
  571. }
  572. else
  573. {
  574. unsigned* dest = (unsigned*)indexData + startIndexOffset;
  575. for (unsigned j = 0; j < mesh->mNumFaces; ++j)
  576. writeLargeIndices(dest, mesh, j, startVertexOffset);
  577. }
  578. // Build the vertex data
  579. // If there are bones, get blend data
  580. std::vector<std::vector<unsigned char> > blendIndices;
  581. std::vector<std::vector<float> > blendWeights;
  582. std::vector<unsigned> boneMappings;
  583. if (model.mBones.size())
  584. getBlendData(model, mesh, boneMappings, blendIndices, blendWeights);
  585. float* dest = (float*)((unsigned char*)vertexData + startVertexOffset * vb->getVertexSize());
  586. for (unsigned j = 0; j < mesh->mNumVertices; ++j)
  587. writeVertex(dest, mesh, j, elementMask, box, vertexTransform, normalTransform, blendIndices, blendWeights);
  588. // Define the geometry
  589. geom->setIndexBuffer(ib);
  590. geom->setVertexBuffer(0, vb);
  591. geom->setDrawRange(TRIANGLE_LIST, startIndexOffset, mesh->mNumFaces * 3, true);
  592. outModel->setNumGeometryLodLevels(i, 1);
  593. outModel->setGeometry(i, 0, geom);
  594. if (model.mBones.size() > MAX_SKIN_MATRICES)
  595. allBoneMappings.push_back(boneMappings);
  596. startVertexOffset += mesh->mNumVertices;
  597. startIndexOffset += mesh->mNumFaces * 3;
  598. }
  599. }
  600. outModel->setBoundingBox(box);
  601. // Build skeleton if necessary
  602. if (model.mBones.size())
  603. {
  604. Skeleton skeleton;
  605. std::vector<SharedPtr<Bone> > srcBones;
  606. for (unsigned i = 0; i < model.mBones.size(); ++i)
  607. {
  608. aiNode* boneNode = model.mBones[i];
  609. std::string boneName(toStdString(boneNode->mName));
  610. srcBones.push_back(SharedPtr<Bone>(new Bone(0, boneName)));
  611. srcBones[i]->setRootBone(srcBones[0]);
  612. aiMatrix4x4 transform;
  613. Vector3 pos, scale;
  614. Quaternion rot;
  615. transform = boneNode->mTransformation;
  616. // Get offset information if exists
  617. srcBones[i]->setOffsetMatrix(getOffsetMatrix(model, boneName, true));
  618. // Make the root bone transform relative to the model's root node, if it is not already
  619. if (boneNode == model.mRootBone)
  620. transform = getDerivedTransform(transform, boneNode, model.mRootNode);
  621. getPosRotScale(transform, pos, rot, scale);
  622. srcBones[i]->setInitialTransform(pos, rot, scale);
  623. srcBones[i]->setRadius(model.mBoneRadii[i]);
  624. srcBones[i]->setBoundingBox(model.mBoneHitboxes[i]);
  625. }
  626. // Set the bone hierarchy
  627. for (unsigned i = 1; i < model.mBones.size(); ++i)
  628. {
  629. std::string parentName = toStdString(model.mBones[i]->mParent->mName);
  630. for (unsigned j = 0; j < srcBones.size(); ++j)
  631. {
  632. if ((srcBones[j]->getName() == parentName) && (i != j))
  633. {
  634. srcBones[j]->addChild(srcBones[i]);
  635. break;
  636. }
  637. }
  638. }
  639. skeleton.setBones(srcBones, srcBones[0]);
  640. outModel->setSkeleton(skeleton);
  641. if (model.mBones.size() > MAX_SKIN_MATRICES)
  642. outModel->setGeometryBoneMappings(allBoneMappings);
  643. }
  644. File outFile(model.mOutName, FILE_WRITE);
  645. outModel->save(outFile);
  646. }
  647. void buildAndSaveAnimations(ExportModel& model)
  648. {
  649. for (unsigned i = 0; i < model.mAnimations.size(); ++i)
  650. {
  651. aiAnimation* anim = model.mAnimations[i];
  652. std::string animName = toStdString(anim->mName);
  653. if (animName.empty())
  654. animName = "Anim" + toString(i + 1);
  655. std::string animOutName = getPath(model.mOutName) + getFileName(model.mOutName) + "_" + animName + ".ani";
  656. SharedPtr<Animation> outAnim(new Animation());
  657. float tickConversion = 1.0f / (float)anim->mTicksPerSecond;
  658. outAnim->setAnimationName(animName);
  659. outAnim->setLength((float)anim->mDuration * tickConversion);
  660. std::cout << "Writing animation " << animName << " length " << outAnim->getLength() << std::endl;
  661. std::vector<AnimationTrack> tracks;
  662. for (unsigned j = 0; j < anim->mNumChannels; ++j)
  663. {
  664. aiNodeAnim* channel = anim->mChannels[j];
  665. std::string channelName = toStdString(channel->mNodeName);
  666. unsigned boneIndex = getBoneIndex(model, channelName);
  667. if (boneIndex == M_MAX_UNSIGNED)
  668. {
  669. std::cout << "Warning: skipping animation track " << channelName << " not found in model skeleton" << std::endl;
  670. continue;
  671. }
  672. aiNode* boneNode = model.mBones[boneIndex];
  673. AnimationTrack track;
  674. track.mName = channelName;
  675. track.mNameHash = StringHash(channelName);
  676. // Check which channels are used
  677. track.mChannelMask = 0;
  678. if (channel->mNumPositionKeys > 1)
  679. track.mChannelMask |= CHANNEL_POSITION;
  680. if (channel->mNumRotationKeys > 1)
  681. track.mChannelMask |= CHANNEL_ROTATION;
  682. if (channel->mNumScalingKeys > 1)
  683. track.mChannelMask |= CHANNEL_SCALE;
  684. // Check for redundant identity scale in all keyframes and remove in that case
  685. if (track.mChannelMask & CHANNEL_SCALE)
  686. {
  687. bool redundantScale = true;
  688. for (unsigned k = 0; k < channel->mNumScalingKeys; ++k)
  689. {
  690. float SCALE_EPSILON = 0.000001f;
  691. Vector3 scaleVec = toVector3(channel->mScalingKeys[k].mValue);
  692. if ((fabsf(scaleVec.mX - 1.0f) >= SCALE_EPSILON) || (fabsf(scaleVec.mY - 1.0f) >= SCALE_EPSILON) ||
  693. (fabsf(scaleVec.mZ - 1.0f) >= SCALE_EPSILON))
  694. {
  695. redundantScale = false;
  696. break;
  697. }
  698. }
  699. if (redundantScale)
  700. track.mChannelMask &= ~CHANNEL_SCALE;
  701. }
  702. if (!track.mChannelMask)
  703. std::cout << "Warning: skipping animation track " << channelName << " with no keyframes" << std::endl;
  704. // Currently only same amount of keyframes is supported
  705. // Note: should also check the times of individual keyframes for match
  706. if (((channel->mNumPositionKeys > 1) && (channel->mNumRotationKeys > 1) && (channel->mNumPositionKeys != channel->mNumRotationKeys)) ||
  707. ((channel->mNumPositionKeys > 1) && (channel->mNumScalingKeys > 1) && (channel->mNumPositionKeys != channel->mNumScalingKeys)) ||
  708. ((channel->mNumRotationKeys > 1) && (channel->mNumScalingKeys > 1) && (channel->mNumRotationKeys != channel->mNumScalingKeys)))
  709. {
  710. std::cout << "Warning: differing amounts of channel keyframes, skipping animation track " << channelName << std::endl;
  711. continue;
  712. }
  713. unsigned keyFrames = channel->mNumPositionKeys;
  714. if (channel->mNumRotationKeys > keyFrames)
  715. keyFrames = channel->mNumRotationKeys;
  716. if (channel->mNumScalingKeys > keyFrames)
  717. keyFrames = channel->mNumScalingKeys;
  718. for (unsigned k = 0; k < keyFrames; ++k)
  719. {
  720. AnimationKeyFrame kf;
  721. kf.mTime = 0.0f;
  722. kf.mPosition = Vector3::sZero;
  723. kf.mRotation = Quaternion::sIdentity;
  724. kf.mScale = Vector3::sUnity;
  725. // Get time for the keyframe
  726. if ((track.mChannelMask & CHANNEL_POSITION) && (k < channel->mNumPositionKeys))
  727. kf.mTime = (float)channel->mPositionKeys[k].mTime * tickConversion;
  728. else if ((track.mChannelMask & CHANNEL_ROTATION) && (k < channel->mNumRotationKeys))
  729. kf.mTime = (float)channel->mRotationKeys[k].mTime * tickConversion;
  730. else if ((track.mChannelMask & CHANNEL_SCALE) && (k < channel->mNumScalingKeys))
  731. kf.mTime = (float)channel->mScalingKeys[k].mTime * tickConversion;
  732. // Start with the bone's base transform
  733. aiMatrix4x4 boneTransform = boneNode->mTransformation;
  734. aiVector3D pos, scale;
  735. aiQuaternion rot;
  736. boneTransform.Decompose(scale, rot, pos);
  737. // Then apply the active channels
  738. if ((track.mChannelMask & CHANNEL_POSITION) && (k < channel->mNumPositionKeys))
  739. pos = channel->mPositionKeys[k].mValue;
  740. if ((track.mChannelMask & CHANNEL_ROTATION) && (k < channel->mNumRotationKeys))
  741. rot = channel->mRotationKeys[k].mValue;
  742. if ((track.mChannelMask & CHANNEL_SCALE) && (k < channel->mNumScalingKeys))
  743. scale = channel->mScalingKeys[k].mValue;
  744. // If root bone, transform with the model root node transform
  745. if (!boneIndex)
  746. {
  747. aiMatrix4x4 transMat, scaleMat, rotMat;
  748. aiMatrix4x4::Translation(pos, transMat);
  749. aiMatrix4x4::Scaling(scale, scaleMat);
  750. rotMat = aiMatrix4x4(rot.GetMatrix());
  751. aiMatrix4x4 tform = transMat * rotMat * scaleMat;
  752. tform = getDerivedTransform(tform, boneNode, model.mRootNode);
  753. tform.Decompose(scale, rot, pos);
  754. }
  755. if (track.mChannelMask & CHANNEL_POSITION)
  756. kf.mPosition = toVector3(pos);
  757. if (track.mChannelMask & CHANNEL_ROTATION)
  758. kf.mRotation = toQuaternion(rot);
  759. if (track.mChannelMask & CHANNEL_SCALE)
  760. kf.mScale = toVector3(scale);
  761. track.mKeyFrames.push_back(kf);
  762. }
  763. tracks.push_back(track);
  764. }
  765. outAnim->setTracks(tracks);
  766. File outFile(animOutName, FILE_WRITE);
  767. outAnim->save(outFile);
  768. }
  769. }
  770. void exportScene(const aiScene* scene, aiNode* rootNode, const std::string& outName, const std::string& resourcePath, bool localIDs,
  771. bool noExtensions, bool saveBinary)
  772. {
  773. if (outName.empty())
  774. errorExit("No output file defined");
  775. ExportScene outScene;
  776. outScene.mOutName = outName;
  777. outScene.mResourcePath = resourcePath;
  778. outScene.mLocalIDs = localIDs;
  779. outScene.mNoExtensions = noExtensions;
  780. outScene.mSaveBinary = saveBinary;
  781. outScene.mScene = scene;
  782. outScene.mRootNode = rootNode;
  783. collectSceneModels(outScene, rootNode);
  784. collectSceneNodes(outScene, rootNode);
  785. // Save models
  786. try
  787. {
  788. for (unsigned i = 0; i < outScene.mModels.size(); ++i)
  789. buildAndSaveModel(outScene.mModels[i]);
  790. }
  791. catch (...)
  792. {
  793. }
  794. // Save scene
  795. buildAndSaveScene(outScene);
  796. }
  797. void collectSceneModels(ExportScene& scene, aiNode* node)
  798. {
  799. std::vector<std::pair<aiNode*, aiMesh*> > meshes = getMeshesUnderNode(scene.mScene, node);
  800. // If meshes encountered, do not recurse further, but build a model for export
  801. if (meshes.size())
  802. {
  803. ExportModel model;
  804. model.mScene = scene.mScene;
  805. model.mRootNode = node;
  806. model.mOutName = getPath(scene.mOutName) + toStdString(node->mName) + ".mdl";
  807. std::cout << "Found model " << model.mOutName << std::endl;
  808. for (unsigned i = 0; i < meshes.size(); ++i)
  809. {
  810. aiMesh* mesh = meshes[i].second;
  811. unsigned meshIndex = getMeshIndex(scene.mScene, mesh);
  812. model.mMeshIndices.insert(meshIndex);
  813. model.mMeshes.push_back(mesh);
  814. model.mMeshNodes.push_back(meshes[i].first);
  815. model.mTotalVertices += mesh->mNumVertices;
  816. model.mTotalIndices += mesh->mNumFaces * 3;
  817. }
  818. // Check if a model with identical mesh indices already exists. If yes, do not export twice
  819. bool unique = true;
  820. for (unsigned i = 0; i < scene.mModels.size(); ++i)
  821. {
  822. if (scene.mModels[i].mMeshIndices == model.mMeshIndices)
  823. {
  824. unique = false;
  825. break;
  826. }
  827. }
  828. if (unique)
  829. {
  830. collectBones(model);
  831. buildBoneCollisionInfo(model);
  832. scene.mModels.push_back(model);
  833. }
  834. return;
  835. }
  836. // If no meshes found, recurse to child nodes
  837. for (unsigned i = 0; i < node->mNumChildren; ++i)
  838. collectSceneModels(scene, node->mChildren[i]);
  839. }
  840. void collectSceneNodes(ExportScene& scene, aiNode* node)
  841. {
  842. std::set<unsigned> meshIndices = getMeshesUnderNodeSet(node);;
  843. if (meshIndices.size())
  844. {
  845. // Check if a matching set of mesh indices is found from the models we are going to write (should be)
  846. for (unsigned i = 0; i < scene.mModels.size(); ++i)
  847. {
  848. if (scene.mModels[i].mMeshIndices == meshIndices)
  849. {
  850. std::cout << "Found node " << toStdString(node->mName) << std::endl;
  851. scene.mNodes.push_back(node);
  852. scene.mNodeModelIndices.push_back(i);
  853. break;
  854. }
  855. }
  856. return;
  857. }
  858. // If no meshes found, recurse to child nodes
  859. for (unsigned i = 0; i < node->mNumChildren; ++i)
  860. collectSceneNodes(scene, node->mChildren[i]);
  861. }
  862. void buildAndSaveScene(ExportScene& scene)
  863. {
  864. std::cout << "Writing scene" << std::endl;
  865. SharedPtr<Scene> outScene(new Scene(0, getFileName(scene.mOutName)));
  866. if (!scene.mNoExtensions)
  867. {
  868. //! \todo Make the physics properties configurable
  869. PhysicsWorld* physicsWorld = new PhysicsWorld(outScene);
  870. physicsWorld->setGravity(Vector3(0.0f, -9.81f, 0.0f));
  871. outScene->addExtension(physicsWorld);
  872. //! \todo Make the octree properties configurable, or detect from the scene contents
  873. Octree* octree = new Octree(BoundingBox(-1000.0f, 1000.0f), 8, true);
  874. outScene->addExtension(octree);
  875. }
  876. std::map<std::string, SharedPtr<Material> > dummyMaterials;
  877. for (unsigned i = 0; i < scene.mNodes.size(); ++i)
  878. {
  879. const ExportModel& model = scene.mModels[scene.mNodeModelIndices[i]];
  880. // Create a simple entity and static model component for each node
  881. Entity* entity = outScene->createEntity(toStdString(scene.mNodes[i]->mName), scene.mLocalIDs);
  882. StaticModel* staticModel = new StaticModel();
  883. entity->addComponent(staticModel);
  884. // Create a dummy model so that the reference can be stored
  885. std::string modelPath = scene.mResourcePath + getFileNameAndExtension(model.mOutName);
  886. SharedPtr<Model> dummyModel(new Model(0, modelPath));
  887. dummyModel->setNumGeometries(model.mMeshes.size());
  888. staticModel->setModel(dummyModel);
  889. // Set a flattened transform
  890. Vector3 pos, scale;
  891. Quaternion rot;
  892. getPosRotScale(getDerivedTransform(scene.mNodes[i], 0), pos, rot, scale);
  893. staticModel->setTransform(pos, rot, scale);
  894. // Set materials if they are known
  895. for (unsigned j = 0; j < model.mMeshes.size(); ++j)
  896. {
  897. aiMaterial* material = scene.mScene->mMaterials[model.mMeshes[j]->mMaterialIndex];
  898. aiString matNameStr;
  899. material->Get(AI_MATKEY_NAME, matNameStr);
  900. std::string matName = toStdString(matNameStr);
  901. if (!matName.empty())
  902. {
  903. std::string matPath = scene.mResourcePath + matName + ".xml";
  904. // Create a dummy material so that the reference can be stored
  905. if (dummyMaterials.find(matName) == dummyMaterials.end())
  906. dummyMaterials[matName] = new Material(matPath);
  907. staticModel->setMaterial(j, dummyMaterials[matName]);
  908. }
  909. }
  910. }
  911. File file(scene.mOutName, FILE_WRITE);
  912. if (!scene.mSaveBinary)
  913. outScene->saveXML(file);
  914. else
  915. outScene->save(file);
  916. }
  917. void exportMaterials(const aiScene* scene, const std::string& outName, const std::string& resourcePath)
  918. {
  919. for (unsigned i = 0; i < scene->mNumMaterials; ++i)
  920. {
  921. try
  922. {
  923. buildAndSaveMaterial(scene->mMaterials[i], outName, resourcePath);
  924. }
  925. catch (...)
  926. {
  927. }
  928. }
  929. }
  930. void buildAndSaveMaterial(aiMaterial* material, const std::string& outName, const std::string& resourcePath)
  931. {
  932. // Material must have name so it can be successfully saved
  933. aiString matNameStr;
  934. material->Get(AI_MATKEY_NAME, matNameStr);
  935. std::string matName = toStdString(matNameStr);
  936. if (matName.empty())
  937. return;
  938. std::cout << "Writing material " << matName << std::endl;
  939. // Do not actually create a material instance, but instead craft an xml file manually, defining a suitable base material
  940. XMLFile outMaterial;
  941. XMLElement materialElem = outMaterial.createRootElement("material");
  942. std::string diffuseTexName;
  943. std::string normalTexName;
  944. Color diffuseColor;
  945. bool hasAlpha = false;
  946. float specIntensity = 0.0f;
  947. float specPower = 1.0f;
  948. aiString stringVal;
  949. float floatVal;
  950. aiColor3D colorVal;
  951. if (material->Get(AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0), stringVal) == AI_SUCCESS)
  952. diffuseTexName = getFileNameAndExtension(toStdString(stringVal));
  953. if (material->Get(AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0), stringVal) == AI_SUCCESS)
  954. normalTexName = getFileNameAndExtension(toStdString(stringVal));
  955. if (material->Get(AI_MATKEY_COLOR_DIFFUSE, colorVal) == AI_SUCCESS)
  956. diffuseColor = Color(colorVal.r, colorVal.g, colorVal.b);
  957. if (material->Get(AI_MATKEY_OPACITY, floatVal) == AI_SUCCESS)
  958. {
  959. if (floatVal < 1.0f)
  960. hasAlpha = true;
  961. diffuseColor.mA = floatVal;
  962. }
  963. if (material->Get(AI_MATKEY_SHININESS, floatVal) == AI_SUCCESS)
  964. specPower = floatVal;
  965. if (material->Get(AI_MATKEY_SHININESS_STRENGTH, floatVal) == AI_SUCCESS)
  966. specIntensity = floatVal;
  967. std::string baseMatName = "Materials/Default";
  968. if (!diffuseTexName.empty())
  969. {
  970. baseMatName += "Diff";
  971. if (!normalTexName.empty())
  972. baseMatName += "Normal";
  973. }
  974. if (hasAlpha)
  975. baseMatName += "Alpha";
  976. XMLElement baseElem = materialElem.createChildElement("base");
  977. baseElem.setString("name", baseMatName + ".xml");
  978. XMLElement techniqueElem = materialElem.createChildElement("technique");
  979. if (!diffuseTexName.empty())
  980. {
  981. XMLElement diffuseElem = techniqueElem.createChildElement("texture");
  982. diffuseElem.setString("unit", "diffuse");
  983. diffuseElem.setString("name", resourcePath + diffuseTexName);
  984. }
  985. if (!normalTexName.empty())
  986. {
  987. XMLElement normalElem = techniqueElem.createChildElement("texture");
  988. normalElem.setString("unit", "diffuse");
  989. normalElem.setString("name", resourcePath + normalTexName);
  990. }
  991. XMLElement diffuseColorElem = techniqueElem.createChildElement("parameter");
  992. diffuseColorElem.setString("name", "MatDiffColor");
  993. diffuseColorElem.setColor("value", diffuseColor);
  994. XMLElement specularElem = techniqueElem.createChildElement("parameter");
  995. specularElem.setString("name", "MatSpecProperties");
  996. specularElem.setVector2("value", Vector2(specIntensity, specPower));
  997. File outFile(getPath(outName) + matName + ".xml", FILE_WRITE);
  998. outMaterial.save(outFile);
  999. }
  1000. std::set<unsigned> getMeshesUnderNodeSet(aiNode* node)
  1001. {
  1002. std::set<unsigned> ret;
  1003. // Do not check this model directly, but rather check if there are meshes in the immediate children
  1004. for (unsigned i = 0; i < node->mNumChildren; ++i)
  1005. {
  1006. aiNode* childNode = node->mChildren[i];
  1007. for (unsigned j = 0; j < childNode->mNumMeshes; ++j)
  1008. ret.insert(childNode->mMeshes[j]);
  1009. }
  1010. return ret;
  1011. }
  1012. std::vector<std::pair<aiNode*, aiMesh*> > getMeshesUnderNode(const aiScene* scene, aiNode* node)
  1013. {
  1014. std::vector<std::pair<aiNode*, aiMesh*> > ret;
  1015. // Do not check this model directly, but rather check if there are meshes in the immediate children
  1016. for (unsigned i = 0; i < node->mNumChildren; ++i)
  1017. {
  1018. aiNode* childNode = node->mChildren[i];
  1019. for (unsigned j = 0; j < childNode->mNumMeshes; ++j)
  1020. ret.push_back(std::make_pair(childNode, scene->mMeshes[childNode->mMeshes[j]]));
  1021. }
  1022. return ret;
  1023. }
  1024. unsigned getMeshIndex(const aiScene* scene, aiMesh* mesh)
  1025. {
  1026. for (unsigned i = 0; i < scene->mNumMeshes; ++i)
  1027. {
  1028. if (scene->mMeshes[i] == mesh)
  1029. return i;
  1030. }
  1031. return M_MAX_UNSIGNED;
  1032. }
  1033. unsigned getBoneIndex(ExportModel& model, const std::string& boneName)
  1034. {
  1035. for (unsigned i = 0; i < model.mBones.size(); ++i)
  1036. {
  1037. if (toStdString(model.mBones[i]->mName) == boneName)
  1038. return i;
  1039. }
  1040. return M_MAX_UNSIGNED;
  1041. }
  1042. aiBone* getMeshBone(ExportModel& model, const std::string& boneName)
  1043. {
  1044. for (unsigned i = 0; i < model.mMeshes.size(); ++i)
  1045. {
  1046. aiMesh* mesh = model.mMeshes[i];
  1047. for (unsigned j = 0; j < mesh->mNumBones; ++j)
  1048. {
  1049. aiBone* bone = mesh->mBones[j];
  1050. if (toStdString(bone->mName) == boneName)
  1051. return bone;
  1052. }
  1053. }
  1054. return 0;
  1055. }
  1056. Matrix4x3 getOffsetMatrix(ExportModel& model, const std::string& boneName, bool useMeshTransform)
  1057. {
  1058. for (unsigned i = 0; i < model.mMeshes.size(); ++i)
  1059. {
  1060. aiMesh* mesh = model.mMeshes[i];
  1061. aiNode* node = model.mMeshNodes[i];
  1062. for (unsigned j = 0; j < mesh->mNumBones; ++j)
  1063. {
  1064. aiBone* bone = mesh->mBones[j];
  1065. if (toStdString(bone->mName) == boneName)
  1066. {
  1067. aiMatrix4x4 offset = bone->mOffsetMatrix;
  1068. if (useMeshTransform)
  1069. {
  1070. aiMatrix4x4 nodeDerivedInverse = getDerivedTransform(node, model.mRootNode);
  1071. nodeDerivedInverse.Inverse();
  1072. offset *= nodeDerivedInverse;
  1073. }
  1074. Matrix4x3 ret;
  1075. memcpy(&ret.m00, &offset.a1, sizeof(Matrix4x3));
  1076. return ret;
  1077. }
  1078. }
  1079. }
  1080. return Matrix4x3::sIdentity;
  1081. }
  1082. void getBlendData(ExportModel& model, aiMesh* mesh, std::vector<unsigned>& boneMappings, std::vector<std::vector<unsigned char> >&
  1083. blendIndices, std::vector<std::vector<float> >& blendWeights)
  1084. {
  1085. blendIndices.resize(mesh->mNumVertices);
  1086. blendWeights.resize(mesh->mNumVertices);
  1087. boneMappings.clear();
  1088. // If model has more bones than can fit vertex shader parameters, write the per-geometry mappings
  1089. if (model.mBones.size() > MAX_SKIN_MATRICES)
  1090. {
  1091. if (mesh->mNumBones > MAX_SKIN_MATRICES)
  1092. errorExit("Geometry has too many bone influences");
  1093. boneMappings.resize(mesh->mNumBones);
  1094. for (unsigned i = 0; i < mesh->mNumBones; ++i)
  1095. {
  1096. aiBone* bone = mesh->mBones[i];
  1097. std::string boneName = toStdString(bone->mName);
  1098. unsigned globalIndex = getBoneIndex(model, boneName);
  1099. if (globalIndex == M_MAX_UNSIGNED)
  1100. errorExit("Bone " + boneName + " not found");
  1101. boneMappings[i] = globalIndex;
  1102. for (unsigned j = 0; j < bone->mNumWeights; ++j)
  1103. {
  1104. unsigned vertex = bone->mWeights[j].mVertexId;
  1105. blendIndices[vertex].push_back(i);
  1106. blendWeights[vertex].push_back(bone->mWeights[j].mWeight);
  1107. if (blendWeights[vertex].size() > 4)
  1108. errorExit("More than 4 bone influences on vertex");
  1109. }
  1110. }
  1111. }
  1112. else
  1113. {
  1114. for (unsigned i = 0; i < mesh->mNumBones; ++i)
  1115. {
  1116. aiBone* bone = mesh->mBones[i];
  1117. std::string boneName = toStdString(bone->mName);
  1118. unsigned globalIndex = getBoneIndex(model, boneName);
  1119. if (globalIndex == M_MAX_UNSIGNED)
  1120. errorExit("Bone " + boneName + " not found");
  1121. for (unsigned j = 0; j < bone->mNumWeights; ++j)
  1122. {
  1123. unsigned vertex = bone->mWeights[j].mVertexId;
  1124. blendIndices[vertex].push_back(globalIndex);
  1125. blendWeights[vertex].push_back(bone->mWeights[j].mWeight);
  1126. if (blendWeights[vertex].size() > 4)
  1127. errorExit("More than 4 bone influences on vertex");
  1128. }
  1129. }
  1130. }
  1131. }
  1132. void writeShortIndices(unsigned short*& dest, aiMesh* mesh, unsigned index, unsigned offset)
  1133. {
  1134. *dest++ = mesh->mFaces[index].mIndices[0] + offset;
  1135. *dest++ = mesh->mFaces[index].mIndices[1] + offset;
  1136. *dest++ = mesh->mFaces[index].mIndices[2] + offset;
  1137. }
  1138. void writeLargeIndices(unsigned*& dest, aiMesh* mesh, unsigned index, unsigned offset)
  1139. {
  1140. *dest++ = mesh->mFaces[index].mIndices[0] + offset;
  1141. *dest++ = mesh->mFaces[index].mIndices[1] + offset;
  1142. *dest++ = mesh->mFaces[index].mIndices[2] + offset;
  1143. }
  1144. void writeVertex(float*& dest, aiMesh* mesh, unsigned index, unsigned elementMask, BoundingBox& box,
  1145. const Matrix4x3& vertexTransform, const Matrix3& normalTransform, std::vector<std::vector<unsigned char> >& blendIndices,
  1146. std::vector<std::vector<float> >& blendWeights)
  1147. {
  1148. Vector3 vertex = vertexTransform * toVector3(mesh->mVertices[index]);
  1149. box.merge(vertex);
  1150. *dest++ = vertex.mX;
  1151. *dest++ = vertex.mY;
  1152. *dest++ = vertex.mZ;
  1153. if (elementMask & MASK_NORMAL)
  1154. {
  1155. Vector3 normal = normalTransform * toVector3(mesh->mNormals[index]);
  1156. *dest++ = normal.mX;
  1157. *dest++ = normal.mY;
  1158. *dest++ = normal.mZ;
  1159. }
  1160. if (elementMask & MASK_COLOR)
  1161. {
  1162. *((unsigned*)dest) = getD3DColor(Color(mesh->mColors[0][index].r, mesh->mColors[0][index].g, mesh->mColors[0][index].b,
  1163. mesh->mColors[0][index].a));
  1164. ++dest;
  1165. }
  1166. if (elementMask & MASK_TEXCOORD1)
  1167. {
  1168. Vector3 texCoord = toVector3(mesh->mTextureCoords[0][index]);
  1169. *dest++ = texCoord.mX;
  1170. *dest++ = texCoord.mY;
  1171. }
  1172. if (elementMask & MASK_TEXCOORD2)
  1173. {
  1174. Vector3 texCoord = toVector3(mesh->mTextureCoords[1][index]);
  1175. *dest++ = texCoord.mX;
  1176. *dest++ = texCoord.mY;
  1177. }
  1178. if (elementMask & MASK_TANGENT)
  1179. {
  1180. Vector3 tangent = normalTransform * toVector3(mesh->mTangents[index]);
  1181. Vector3 normal = normalTransform * toVector3(mesh->mNormals[index]);
  1182. Vector3 bitangent = normalTransform * toVector3(mesh->mBitangents[index]);
  1183. // Check handedness
  1184. float w = 1.0f;
  1185. if ((tangent.crossProduct(normal)).dotProduct(bitangent) < 0.5f)
  1186. w = -1.0f;
  1187. *dest++ = tangent.mX;
  1188. *dest++ = tangent.mY;
  1189. *dest++ = tangent.mZ;
  1190. *dest++ = w;
  1191. }
  1192. if (elementMask & MASK_BLENDWEIGHTS)
  1193. {
  1194. for (unsigned i = 0; i < 4; ++i)
  1195. {
  1196. if (i < blendWeights[index].size())
  1197. *dest++ = blendWeights[index][i];
  1198. else
  1199. *dest++ = 0.0f;
  1200. }
  1201. }
  1202. if (elementMask & MASK_BLENDINDICES)
  1203. {
  1204. unsigned char* destBytes = (unsigned char*)dest;
  1205. ++dest;
  1206. for (unsigned i = 0; i < 4; ++i)
  1207. {
  1208. if (i < blendIndices[index].size())
  1209. *destBytes++ = blendIndices[index][i];
  1210. else
  1211. *destBytes++ = 0;
  1212. }
  1213. }
  1214. }
  1215. unsigned getElementMask(aiMesh* mesh)
  1216. {
  1217. unsigned elementMask = MASK_POSITION;
  1218. if (mesh->HasNormals())
  1219. elementMask |= MASK_NORMAL;
  1220. if (mesh->HasTangentsAndBitangents())
  1221. elementMask |= MASK_TANGENT;
  1222. if (mesh->GetNumColorChannels() > 0)
  1223. elementMask |= MASK_COLOR;
  1224. if (mesh->GetNumUVChannels() > 0)
  1225. elementMask |= MASK_TEXCOORD1;
  1226. if (mesh->GetNumUVChannels() > 1)
  1227. elementMask |= MASK_TEXCOORD2;
  1228. if (mesh->HasBones())
  1229. elementMask |= (MASK_BLENDWEIGHTS | MASK_BLENDINDICES);
  1230. return elementMask;
  1231. }
  1232. aiNode* findNode(const std::string& name, aiNode* rootNode, bool caseSensitive)
  1233. {
  1234. if (!rootNode)
  1235. return 0;
  1236. if (!caseSensitive)
  1237. {
  1238. if (toLower(toStdString(rootNode->mName)) == toLower(name))
  1239. return rootNode;
  1240. }
  1241. else
  1242. {
  1243. if (toStdString(rootNode->mName) == name)
  1244. return rootNode;
  1245. }
  1246. for (unsigned i = 0; i < rootNode->mNumChildren; ++i)
  1247. {
  1248. aiNode* found = findNode(name, rootNode->mChildren[i], caseSensitive);
  1249. if (found)
  1250. return found;
  1251. }
  1252. return 0;
  1253. }
  1254. std::string toStdString(const aiString& str)
  1255. {
  1256. if ((!str.data) || (!str.length))
  1257. return std::string();
  1258. else
  1259. return std::string(str.data);
  1260. }
  1261. Vector3 toVector3(const aiVector3D& vec)
  1262. {
  1263. return Vector3(vec.x, vec.y, vec.z);
  1264. }
  1265. Vector2 toVector2(const aiVector2D& vec)
  1266. {
  1267. return Vector2(vec.x, vec.y);
  1268. }
  1269. Quaternion toQuaternion(const aiQuaternion& quat)
  1270. {
  1271. return Quaternion(quat.w, quat.x, quat.y, quat.z);
  1272. }
  1273. aiMatrix4x4 getDerivedTransform(aiNode* node, aiNode* rootNode)
  1274. {
  1275. aiMatrix4x4 current = node->mTransformation;
  1276. // If basenode is defined, go only up to it in the parent chain
  1277. while ((node->mParent) && (node != rootNode))
  1278. {
  1279. node = node->mParent;
  1280. current = node->mTransformation * current;
  1281. }
  1282. return current;
  1283. }
  1284. aiMatrix4x4 getDerivedTransform(aiMatrix4x4 transform, aiNode* node, aiNode* rootNode)
  1285. {
  1286. // If basenode is defined, go only up to it in the parent chain
  1287. while ((node->mParent) && (node != rootNode))
  1288. {
  1289. node = node->mParent;
  1290. transform = node->mTransformation * transform;
  1291. }
  1292. return transform;
  1293. }
  1294. void getPosRotScale(const aiMatrix4x4& transform, Vector3& pos, Quaternion& rot, Vector3& scale)
  1295. {
  1296. aiVector3D aiPos;
  1297. aiQuaternion aiRot;
  1298. aiVector3D aiScale;
  1299. transform.Decompose(aiScale, aiRot, aiPos);
  1300. pos = toVector3(aiPos);
  1301. rot = toQuaternion(aiRot);
  1302. scale = toVector3(aiScale);
  1303. }
  1304. void errorExit(const std::string& error)
  1305. {
  1306. throw Exception(error);
  1307. }