2
0

Exporter.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248
  1. // Copyright (C) 2009-2020, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include "Exporter.h"
  6. #include <iostream>
  7. static const char* XML_HEADER = R"(<?xml version="1.0" encoding="UTF-8" ?>)";
  8. #if 0
  9. static aiColor3D srgbToLinear(aiColor3D in)
  10. {
  11. const float p = 1.0f / 2.4f;
  12. aiColor3D out;
  13. out[0] = pow(in[0], p);
  14. out[1] = pow(in[1], p);
  15. out[2] = pow(in[2], p);
  16. out[3] = in[3];
  17. return out;
  18. }
  19. /// Convert from sRGB to linear and preserve energy
  20. static aiColor3D computeLightColor(aiColor3D in)
  21. {
  22. float energy = std::max(std::max(in[0], in[1]), in[2]);
  23. if(energy > 1.0)
  24. {
  25. in[0] /= energy;
  26. in[1] /= energy;
  27. in[2] /= energy;
  28. }
  29. else
  30. {
  31. energy = 1.0;
  32. }
  33. in = srgbToLinear(in);
  34. in[0] *= energy;
  35. in[1] *= energy;
  36. in[2] *= energy;
  37. return in;
  38. }
  39. #endif
  40. static std::string getMeshName(const aiMesh& mesh)
  41. {
  42. return std::string(mesh.mName.C_Str());
  43. }
  44. /// Walk the node hierarchy and find the node.
  45. static const aiNode* findNodeWithName(const std::string& name, const aiNode* node, unsigned* depth = nullptr)
  46. {
  47. if(node == nullptr || node->mName.C_Str() == name)
  48. {
  49. return node;
  50. }
  51. if(depth)
  52. {
  53. ++(*depth);
  54. }
  55. const aiNode* out = nullptr;
  56. // Go to children
  57. for(unsigned i = 0; i < node->mNumChildren; i++)
  58. {
  59. out = findNodeWithName(name, node->mChildren[i]);
  60. if(out)
  61. {
  62. break;
  63. }
  64. }
  65. return out;
  66. }
  67. static std::vector<std::string> tokenize(const std::string& source)
  68. {
  69. const char* delimiter = " ";
  70. bool keepEmpty = false;
  71. std::vector<std::string> results;
  72. size_t prev = 0;
  73. size_t next = 0;
  74. while((next = source.find_first_of(delimiter, prev)) != std::string::npos)
  75. {
  76. if(keepEmpty || (next - prev != 0))
  77. {
  78. results.push_back(source.substr(prev, next - prev));
  79. }
  80. prev = next + 1;
  81. }
  82. if(prev < source.size())
  83. {
  84. results.push_back(source.substr(prev));
  85. }
  86. return results;
  87. }
  88. template<int N, typename Arr>
  89. static void stringToFloatArray(const std::string& in, Arr& out)
  90. {
  91. std::vector<std::string> tokens = tokenize(in);
  92. if(tokens.size() != N)
  93. {
  94. ERROR("Failed to parse %s", in.c_str());
  95. }
  96. int count = 0;
  97. for(const std::string& s : tokens)
  98. {
  99. out[count] = std::stof(s);
  100. ++count;
  101. }
  102. }
  103. static void removeScale(aiMatrix4x4& m)
  104. {
  105. aiVector3D xAxis(m.a1, m.b1, m.c1);
  106. aiVector3D yAxis(m.a2, m.b2, m.c2);
  107. aiVector3D zAxis(m.a3, m.b3, m.c3);
  108. float scale = xAxis.Length();
  109. m.a1 /= scale;
  110. m.b1 /= scale;
  111. m.c1 /= scale;
  112. scale = yAxis.Length();
  113. m.a2 /= scale;
  114. m.b2 /= scale;
  115. m.c2 /= scale;
  116. scale = zAxis.Length();
  117. m.a3 /= scale;
  118. m.b3 /= scale;
  119. m.c3 /= scale;
  120. }
  121. static float getUniformScale(const aiMatrix4x4& m)
  122. {
  123. const float SCALE_THRESHOLD = 0.01f; // 1 cm
  124. aiVector3D xAxis(m.a1, m.b1, m.c1);
  125. aiVector3D yAxis(m.a2, m.b2, m.c2);
  126. aiVector3D zAxis(m.a3, m.b3, m.c3);
  127. float scale = xAxis.Length();
  128. if(std::abs(scale - yAxis.Length()) > SCALE_THRESHOLD || std::abs(scale - zAxis.Length()) > SCALE_THRESHOLD)
  129. {
  130. ERROR("No uniform scale in the matrix");
  131. }
  132. return scale;
  133. }
  134. static aiVector3D getNonUniformScale(const aiMatrix4x4& m)
  135. {
  136. aiVector3D xAxis(m.a1, m.b1, m.c1);
  137. aiVector3D yAxis(m.a2, m.b2, m.c2);
  138. aiVector3D zAxis(m.a3, m.b3, m.c3);
  139. aiVector3D scale;
  140. scale[0] = xAxis.Length();
  141. scale[1] = yAxis.Length();
  142. scale[2] = zAxis.Length();
  143. return scale;
  144. }
  145. std::string Exporter::getMaterialName(const aiMaterial& mtl)
  146. {
  147. aiString ainame;
  148. std::string name;
  149. if(mtl.Get(AI_MATKEY_NAME, ainame) == AI_SUCCESS)
  150. {
  151. name = ainame.C_Str();
  152. }
  153. else
  154. {
  155. ERROR("Material's name is missing");
  156. }
  157. return name;
  158. }
  159. aiMatrix4x4 Exporter::toAnkiMatrix(const aiMatrix4x4& in) const
  160. {
  161. static const aiMatrix4x4 toLeftHanded(1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1);
  162. static const aiMatrix4x4 toLeftHandedInv(1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1);
  163. if(m_flipyz)
  164. {
  165. return toLeftHanded * in * toLeftHandedInv;
  166. }
  167. else
  168. {
  169. return in;
  170. }
  171. }
  172. aiMatrix3x3 Exporter::toAnkiMatrix(const aiMatrix3x3& in) const
  173. {
  174. static const aiMatrix3x3 toLeftHanded(1, 0, 0, 0, 0, 1, 0, -1, 0);
  175. static const aiMatrix3x3 toLeftHandedInv(1, 0, 0, 0, 0, -1, 0, 1, 0);
  176. if(m_flipyz)
  177. {
  178. return toLeftHanded * in;
  179. }
  180. else
  181. {
  182. return in;
  183. }
  184. }
  185. void Exporter::writeTransform(const aiMatrix4x4& inmat)
  186. {
  187. aiMatrix4x4 mat = inmat;
  188. std::ofstream& file = m_sceneFile;
  189. float pos[3];
  190. pos[0] = mat[0][3];
  191. pos[1] = mat[1][3];
  192. pos[2] = mat[2][3];
  193. file << "trf = Transform.new()\n";
  194. file << "trf:setOrigin(Vec4.new(" << pos[0] << ", " << pos[1] << ", " << pos[2] << ", 0))\n";
  195. float scale = getUniformScale(mat);
  196. removeScale(mat);
  197. file << "rot = Mat3x4.new()\n";
  198. file << "rot:setAll(";
  199. for(unsigned j = 0; j < 3; j++)
  200. {
  201. for(unsigned i = 0; i < 4; i++)
  202. {
  203. if(i == 3)
  204. {
  205. file << "0";
  206. }
  207. else
  208. {
  209. file << mat[j][i];
  210. }
  211. if(!(i == 3 && j == 2))
  212. {
  213. file << ", ";
  214. }
  215. }
  216. }
  217. file << ")\n";
  218. file << "trf:setRotation(rot)\n";
  219. file << "trf:setScale(" << scale << ")\n";
  220. }
  221. void Exporter::writeNodeTransform(const std::string& node, const aiMatrix4x4& mat)
  222. {
  223. std::ofstream& file = m_sceneFile;
  224. writeTransform(mat);
  225. file << node << ":getSceneNodeBase():getMoveComponent():setLocalTransform(trf)\n";
  226. }
  227. const aiMesh& Exporter::getMeshAt(unsigned index) const
  228. {
  229. assert(index < m_scene->mNumMeshes);
  230. return *m_scene->mMeshes[index];
  231. }
  232. const aiMaterial& Exporter::getMaterialAt(unsigned index) const
  233. {
  234. assert(index < m_scene->mNumMaterials);
  235. return *m_scene->mMaterials[index];
  236. }
  237. std::string Exporter::getModelName(const Model& model) const
  238. {
  239. std::string name = getMeshName(getMeshAt(model.m_meshIndex));
  240. name += getMaterialName(getMaterialAt(model.m_materialIndex));
  241. return name;
  242. }
  243. void Exporter::exportSkeleton(const aiMesh& mesh) const
  244. {
  245. assert(mesh.HasBones());
  246. std::string name = mesh.mName.C_Str();
  247. std::fstream file;
  248. LOGI("Exporting skeleton %s", name.c_str());
  249. // Find the root bone
  250. unsigned minDepth = 0xFFFFFFFF;
  251. std::string rootBoneName;
  252. for(uint32_t i = 0; i < mesh.mNumBones; i++)
  253. {
  254. const aiBone& bone = *mesh.mBones[i];
  255. unsigned depth = 0;
  256. const aiNode* node = findNodeWithName(bone.mName.C_Str(), m_scene->mRootNode, &depth);
  257. if(!node)
  258. {
  259. ERROR("Bone \"%s\" was not found in the scene hierarchy", bone.mName.C_Str());
  260. }
  261. if(depth < minDepth)
  262. {
  263. minDepth = depth;
  264. rootBoneName = bone.mName.C_Str();
  265. }
  266. }
  267. assert(!rootBoneName.empty());
  268. // Open file
  269. file.open(m_outputDirectory + name + ".ankiskel", std::ios::out);
  270. file << XML_HEADER << "\n";
  271. file << "<skeleton>\n";
  272. file << "\t<bones>\n";
  273. for(uint32_t i = 0; i < mesh.mNumBones; i++)
  274. {
  275. const aiBone& bone = *mesh.mBones[i];
  276. file << "\t\t<bone>\n";
  277. // <name>
  278. file << "\t\t\t<name>" << bone.mName.C_Str() << "</name>\n";
  279. // <boneTransform>
  280. aiMatrix4x4 akMat = toAnkiMatrix(bone.mOffsetMatrix);
  281. file << "\t\t\t<boneTransform>";
  282. for(unsigned j = 0; j < 4; j++)
  283. {
  284. for(unsigned i = 0; i < 4; i++)
  285. {
  286. file << akMat[j][i] << " ";
  287. }
  288. }
  289. file << "</boneTransform>\n";
  290. // <transform>
  291. const aiNode* node = findNodeWithName(bone.mName.C_Str(), m_scene->mRootNode);
  292. assert(node);
  293. akMat = toAnkiMatrix(node->mTransformation);
  294. file << "\t\t\t<transform>";
  295. for(unsigned j = 0; j < 4; j++)
  296. {
  297. for(unsigned i = 0; i < 4; i++)
  298. {
  299. file << akMat[j][i] << " ";
  300. }
  301. }
  302. file << "</transform>\n";
  303. // <parent>
  304. if(bone.mName.C_Str() != rootBoneName)
  305. {
  306. file << "\t\t\t<parent>" << node->mParent->mName.C_Str() << "</parent>\n";
  307. }
  308. file << "\t\t</bone>\n";
  309. }
  310. file << "\t</bones>\n";
  311. file << "</skeleton>\n";
  312. }
  313. void Exporter::exportModel(const Model& model) const
  314. {
  315. std::string name = getModelName(model);
  316. LOGI("Exporting model %s", name.c_str());
  317. std::fstream file;
  318. file.open(m_outputDirectory + name + ".ankimdl", std::ios::out);
  319. file << XML_HEADER << '\n';
  320. file << "<model>\n";
  321. file << "\t<modelPatches>\n";
  322. // Start patches
  323. file << "\t\t<modelPatch>\n";
  324. // Write mesh
  325. file << "\t\t\t<mesh>" << m_rpath << getMeshName(getMeshAt(model.m_meshIndex)) << ".ankimesh</mesh>\n";
  326. // Write mesh1
  327. if(!model.m_lod1MeshName.empty())
  328. {
  329. bool found = false;
  330. for(unsigned i = 0; i < m_scene->mNumMeshes; i++)
  331. {
  332. if(m_scene->mMeshes[i]->mName.C_Str() == model.m_lod1MeshName)
  333. {
  334. file << "\t\t\t<mesh1>" << m_rpath << getMeshName(getMeshAt(i)) << ".ankimesh</mesh1>\n";
  335. found = true;
  336. break;
  337. }
  338. }
  339. if(!found)
  340. {
  341. ERROR("Couldn't find the LOD1 %s", model.m_lod1MeshName.c_str());
  342. }
  343. }
  344. // Write material
  345. const aiMaterial& mtl = *m_scene->mMaterials[model.m_materialIndex];
  346. if(mtl.mAnKiProperties.find("material_override") == mtl.mAnKiProperties.end())
  347. {
  348. file << "\t\t\t<material>" << m_rpath << getMaterialName(getMaterialAt(model.m_materialIndex))
  349. << ".ankimtl</material>\n";
  350. }
  351. else
  352. {
  353. file << "\t\t\t<material>" << mtl.mAnKiProperties.at("material_override") << "</material>\n";
  354. }
  355. // End patches
  356. file << "\t\t</modelPatch>\n";
  357. file << "\t</modelPatches>\n";
  358. // Skeleton
  359. const aiMesh& aimesh = *m_scene->mMeshes[model.m_meshIndex];
  360. if(aimesh.HasBones())
  361. {
  362. exportSkeleton(aimesh);
  363. file << "\t<skeleton>" << m_rpath << aimesh.mName.C_Str() << ".ankiskel</skeleton>\n";
  364. }
  365. file << "</model>\n";
  366. }
  367. void Exporter::exportLight(const aiLight& light)
  368. {
  369. std::ofstream& file = m_sceneFile;
  370. LOGI("Exporting light %s", light.mName.C_Str());
  371. if(light.mType != aiLightSource_POINT && light.mType != aiLightSource_SPOT
  372. && light.mType != aiLightSource_DIRECTIONAL)
  373. {
  374. LOGW("Skipping light %s. Unsupported type (0x%x)", light.mName.C_Str(), light.mType);
  375. return;
  376. }
  377. if(light.mAttenuationLinear != 0.0)
  378. {
  379. LOGW("Skipping light %s. Linear attenuation is not 0.0", light.mName.C_Str());
  380. return;
  381. }
  382. const char* lightType;
  383. switch(light.mType)
  384. {
  385. case aiLightSource_POINT:
  386. lightType = "Point";
  387. break;
  388. case aiLightSource_SPOT:
  389. lightType = "Spot";
  390. break;
  391. case aiLightSource_DIRECTIONAL:
  392. lightType = "Directional";
  393. break;
  394. default:
  395. lightType = nullptr;
  396. assert(0);
  397. }
  398. file << "\nnode = scene:new" << lightType << "LightNode(\"" << light.mName.C_Str() << "\")\n";
  399. file << "lcomp = node:getSceneNodeBase():getLightComponent()\n";
  400. // Colors
  401. // aiColor3D linear = computeLightColor(light.mColorDiffuse);
  402. aiVector3D linear(light.mColorDiffuse[0], light.mColorDiffuse[1], light.mColorDiffuse[2]);
  403. file << "lcomp:setDiffuseColor(Vec4.new(" << linear[0] << ", " << linear[1] << ", " << linear[2] << ", 1))\n";
  404. // Geometry
  405. switch(light.mType)
  406. {
  407. case aiLightSource_POINT:
  408. {
  409. // At this point I want the radius and have the attenuation factors
  410. // att = Ac + Al*d + Aq*d^2. When d = r then att = 0.0. Also if we assume that Al is 0 then:
  411. // 0 = Ac + Aq*r^2. Solving by r is easy
  412. float r = sqrt(light.mAttenuationConstant / light.mAttenuationQuadratic);
  413. file << "lcomp:setRadius(" << r << ")\n";
  414. }
  415. break;
  416. case aiLightSource_SPOT:
  417. {
  418. float dist = sqrt(light.mAttenuationConstant / light.mAttenuationQuadratic);
  419. float outer = light.mAngleOuterCone;
  420. float inner = light.mAngleInnerCone;
  421. if(outer == inner)
  422. {
  423. inner = outer / 2.0f;
  424. }
  425. file << "lcomp:setInnerAngle(" << inner << ")\n"
  426. << "lcomp:setOuterAngle(" << outer << ")\n"
  427. << "lcomp:setDistance(" << dist << ")\n";
  428. break;
  429. }
  430. case aiLightSource_DIRECTIONAL:
  431. {
  432. break;
  433. }
  434. default:
  435. assert(0);
  436. break;
  437. }
  438. // Transform
  439. const aiNode* node = findNodeWithName(light.mName.C_Str(), m_scene->mRootNode);
  440. if(node == nullptr)
  441. {
  442. ERROR("Couldn't find node for light %s", light.mName.C_Str());
  443. }
  444. aiMatrix4x4 rot;
  445. aiMatrix4x4::RotationX(-3.1415f / 2.0f, rot);
  446. writeNodeTransform("node", toAnkiMatrix(node->mTransformation * rot));
  447. // Extra
  448. if(light.mProperties.find("shadow") != light.mProperties.end())
  449. {
  450. if(light.mProperties.at("shadow") == "true")
  451. {
  452. file << "lcomp:setShadowEnabled(1)\n";
  453. }
  454. else
  455. {
  456. file << "lcomp:setShadowEnabled(0)\n";
  457. }
  458. }
  459. if(light.mProperties.find("lens_flare") != light.mProperties.end())
  460. {
  461. file << "node:loadLensFlare(\"" << light.mProperties.at("lens_flare") << "\")\n";
  462. }
  463. bool lfCompRetrieved = false;
  464. if(light.mProperties.find("lens_flare_first_sprite_size") != light.mProperties.end())
  465. {
  466. if(!lfCompRetrieved)
  467. {
  468. file << "lfcomp = node:getSceneNodeBase():getLensFlareComponent()\n";
  469. lfCompRetrieved = true;
  470. }
  471. aiVector3D vec;
  472. stringToFloatArray<2>(light.mProperties.at("lens_flare_first_sprite_size"), vec);
  473. file << "lfcomp:setFirstFlareSize(Vec2.new(" << vec[0] << ", " << vec[1] << "))\n";
  474. }
  475. if(light.mProperties.find("lens_flare_color") != light.mProperties.end())
  476. {
  477. if(!lfCompRetrieved)
  478. {
  479. file << "lfcomp = node:getSceneNodeBase():getLensFlareComponent()\n";
  480. lfCompRetrieved = true;
  481. }
  482. aiVector3D vec;
  483. stringToFloatArray<4>(light.mProperties.at("lens_flare_color"), vec);
  484. file << "lfcomp:setColorMultiplier(Vec4.new(" << vec[0] << ", " << vec[1] << ", " << vec[2] << ", " << vec[3]
  485. << "))\n";
  486. }
  487. bool eventCreated = false;
  488. if(light.mProperties.find("light_event_intensity") != light.mProperties.end())
  489. {
  490. if(!eventCreated)
  491. {
  492. file << "event = events:newLightEvent(0.0, -1.0, node:getSceneNodeBase())\n";
  493. eventCreated = true;
  494. }
  495. aiVector3D vec;
  496. stringToFloatArray<4>(light.mProperties.at("light_event_intensity"), vec);
  497. file << "event:setIntensityMultiplier(Vec4.new(" << vec[0] << ", " << vec[1] << ", " << vec[2] << ", " << vec[3]
  498. << "))\n";
  499. }
  500. if(light.mProperties.find("light_event_frequency") != light.mProperties.end())
  501. {
  502. if(!eventCreated)
  503. {
  504. file << "event = events:newLightEvent(0.0, -1.0, node:getSceneNodeBase())\n";
  505. eventCreated = true;
  506. }
  507. float vec[2];
  508. stringToFloatArray<2>(light.mProperties.at("light_event_frequency"), vec);
  509. file << "event:setFrequency(" << vec[0] << ", " << vec[1] << ")\n";
  510. }
  511. }
  512. void Exporter::exportAnimation(const aiAnimation& anim, unsigned index)
  513. {
  514. // Get name
  515. std::string name = anim.mName.C_Str();
  516. if(name.size() == 0)
  517. {
  518. name = std::string("unnamed_") + std::to_string(index);
  519. }
  520. // Find if it's skeleton animation
  521. /*bool isSkeletalAnimation = false;
  522. for(uint32_t i = 0; i < scene.mNumMeshes; i++)
  523. {
  524. const aiMesh& mesh = *scene.mMeshes[i];
  525. if(mesh.HasBones())
  526. {
  527. }
  528. }*/
  529. std::fstream file;
  530. LOGI("Exporting animation %s", name.c_str());
  531. file.open(m_outputDirectory + name + ".ankianim", std::ios::out);
  532. file << XML_HEADER << "\n";
  533. file << "<animation>\n";
  534. file << "\t<channels>\n";
  535. for(uint32_t i = 0; i < anim.mNumChannels; i++)
  536. {
  537. const aiNodeAnim& nAnim = *anim.mChannels[i];
  538. file << "\t\t<channel>\n";
  539. // Name
  540. file << "\t\t\t<name>" << nAnim.mNodeName.C_Str() << "</name>\n";
  541. // Positions
  542. file << "\t\t\t<positionKeys>\n";
  543. for(uint32_t j = 0; j < nAnim.mNumPositionKeys; j++)
  544. {
  545. const aiVectorKey& key = nAnim.mPositionKeys[j];
  546. if(m_flipyz)
  547. {
  548. file << "\t\t\t\t<key><time>" << key.mTime << "</time><value>" << key.mValue[0] << " " << key.mValue[2]
  549. << " " << -key.mValue[1] << "</value></key>\n";
  550. }
  551. else
  552. {
  553. file << "\t\t\t\t<key><time>" << key.mTime << "</time><value>" << key.mValue[0] << " " << key.mValue[1]
  554. << " " << key.mValue[2] << "</value></key>\n";
  555. }
  556. }
  557. file << "\t\t\t</positionKeys>\n";
  558. // Rotations
  559. file << "\t\t\t<rotationKeys>\n";
  560. for(uint32_t j = 0; j < nAnim.mNumRotationKeys; j++)
  561. {
  562. const aiQuatKey& key = nAnim.mRotationKeys[j];
  563. aiMatrix3x3 mat = toAnkiMatrix(key.mValue.GetMatrix());
  564. aiQuaternion quat(mat);
  565. // aiQuaternion quat(key.mValue);
  566. file << "\t\t\t\t<key><time>" << key.mTime << "</time>"
  567. << "<value>" << quat.x << " " << quat.y << " " << quat.z << " " << quat.w << "</value></key>\n";
  568. }
  569. file << "\t\t\t</rotationKeys>\n";
  570. // Scale
  571. file << "\t\t\t<scalingKeys>\n";
  572. for(uint32_t j = 0; j < nAnim.mNumScalingKeys; j++)
  573. {
  574. const aiVectorKey& key = nAnim.mScalingKeys[j];
  575. // Note: only uniform scale
  576. file << "\t\t\t\t<key><time>" << key.mTime << "</time>"
  577. << "<value>" << ((key.mValue[0] + key.mValue[1] + key.mValue[2]) / 3.0) << "</value></key>\n";
  578. }
  579. file << "\t\t\t</scalingKeys>\n";
  580. file << "\t\t</channel>\n";
  581. }
  582. file << "\t</channels>\n";
  583. file << "</animation>\n";
  584. }
  585. void Exporter::exportCamera(const aiCamera& cam)
  586. {
  587. std::ofstream& file = m_sceneFile;
  588. LOGI("Exporting camera %s", cam.mName.C_Str());
  589. // Write the main node
  590. file << "\nnode = scene:newPerspectiveCameraNode(\"" << cam.mName.C_Str() << "\")\n";
  591. file << "scene:setActiveCameraNode(node:getSceneNodeBase())\n";
  592. file << "frustumc = node:getSceneNodeBase():getFrustumComponent()\n";
  593. file << "frustumc:setPerspective(" << cam.mClipPlaneNear << ", " << cam.mClipPlaneFar << ", " << cam.mHorizontalFOV
  594. << ", "
  595. << "1.0 / getMainRenderer():getAspectRatio() * " << cam.mHorizontalFOV << ")\n";
  596. // Find the node
  597. const aiNode* node = findNodeWithName(cam.mName.C_Str(), m_scene->mRootNode);
  598. if(node == nullptr)
  599. {
  600. ERROR("Couldn't find node for camera %s", cam.mName.C_Str());
  601. }
  602. aiMatrix4x4 rot;
  603. aiMatrix4x4::RotationX(-3.1415f / 2.0f, rot);
  604. writeNodeTransform("node", toAnkiMatrix(node->mTransformation * rot));
  605. }
  606. void Exporter::load()
  607. {
  608. LOGI("Loading file %s", &m_inputFilename[0]);
  609. const int smoothAngle = 170;
  610. m_importer.SetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, smoothAngle);
  611. unsigned flags = 0
  612. //| aiProcess_FindInstances
  613. | aiProcess_JoinIdenticalVertices
  614. //| aiProcess_SortByPType
  615. | aiProcess_ImproveCacheLocality | aiProcess_OptimizeMeshes | aiProcess_RemoveRedundantMaterials
  616. | aiProcess_CalcTangentSpace | aiProcess_GenSmoothNormals;
  617. const aiScene* scene = m_importer.ReadFile(m_inputFilename, flags | aiProcess_Triangulate);
  618. if(!scene)
  619. {
  620. ERROR("%s", m_importer.GetErrorString());
  621. }
  622. m_scene = scene;
  623. // Load without triangulation
  624. m_importerNoTriangles.SetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, smoothAngle);
  625. scene = m_importerNoTriangles.ReadFile(m_inputFilename, flags);
  626. if(!scene)
  627. {
  628. ERROR("%s", m_importerNoTriangles.GetErrorString());
  629. }
  630. m_sceneNoTriangles = scene;
  631. }
  632. void Exporter::visitNode(const aiNode* ainode)
  633. {
  634. if(ainode == nullptr)
  635. {
  636. return;
  637. }
  638. // For every mesh of this node
  639. for(unsigned i = 0; i < ainode->mNumMeshes; i++)
  640. {
  641. unsigned meshIndex = ainode->mMeshes[i];
  642. unsigned mtlIndex = m_scene->mMeshes[meshIndex]->mMaterialIndex;
  643. // Check properties
  644. std::string lod1MeshName;
  645. std::string collisionMesh;
  646. bool special = false;
  647. GiProbe giProbe;
  648. bool isGiProbe = false;
  649. ParticleEmitter particleEmitter;
  650. bool isParticleEmitter = false;
  651. for(const auto& prop : m_scene->mMeshes[meshIndex]->mProperties)
  652. {
  653. if(prop.first == "particles")
  654. {
  655. particleEmitter.m_filename = prop.second;
  656. particleEmitter.m_transform = toAnkiMatrix(ainode->mTransformation);
  657. special = true;
  658. isParticleEmitter = true;
  659. }
  660. else if(prop.first == "gpu_particles" && prop.second == "true")
  661. {
  662. particleEmitter.m_gpu = true;
  663. }
  664. else if(prop.first == "collision" && prop.second == "true")
  665. {
  666. StaticCollisionNode n;
  667. n.m_meshIndex = meshIndex;
  668. n.m_transform = toAnkiMatrix(ainode->mTransformation);
  669. m_staticCollisionNodes.push_back(n);
  670. special = true;
  671. }
  672. else if(prop.first == "lod1")
  673. {
  674. lod1MeshName = prop.second;
  675. special = false;
  676. }
  677. else if(prop.first == "reflection_probe" && prop.second == "true")
  678. {
  679. ReflectionProbe probe;
  680. aiMatrix4x4 trf = toAnkiMatrix(ainode->mTransformation);
  681. probe.m_position = aiVector3D(trf.a4, trf.b4, trf.c4);
  682. aiVector3D scale(trf.a1, trf.b2, trf.c3);
  683. assert(scale.x > 0.0f && scale.y > 0.0f && scale.z > 0.0f);
  684. aiVector3D half = scale;
  685. probe.m_aabbMin = probe.m_position - half - probe.m_position;
  686. probe.m_aabbMax = probe.m_position + half - probe.m_position;
  687. m_reflectionProbes.push_back(probe);
  688. special = true;
  689. }
  690. else if(prop.first == "gi_probe" && prop.second == "true")
  691. {
  692. GiProbe& probe = giProbe;
  693. aiMatrix4x4 trf = toAnkiMatrix(ainode->mTransformation);
  694. probe.m_position = aiVector3D(trf.a4, trf.b4, trf.c4);
  695. aiVector3D scale(trf.a1, trf.b2, trf.c3);
  696. assert(scale.x > 0.0f && scale.y > 0.0f && scale.z > 0.0f);
  697. aiVector3D half = scale;
  698. probe.m_aabbMin = probe.m_position - half - probe.m_position;
  699. probe.m_aabbMax = probe.m_position + half - probe.m_position;
  700. isGiProbe = true;
  701. special = true;
  702. }
  703. else if(prop.first == "gi_probe_fade_distance")
  704. {
  705. giProbe.m_fadeDistance = std::strtof(prop.second.c_str(), nullptr);
  706. }
  707. else if(prop.first == "gi_probe_cell_size")
  708. {
  709. giProbe.m_cellSize = std::strtof(prop.second.c_str(), nullptr);
  710. }
  711. else if(prop.first == "reflection_proxy" && prop.second == "true")
  712. {
  713. ReflectionProxy proxy;
  714. // Find proxy in the other scene
  715. proxy.m_meshIndex = 0xFFFFFFFF;
  716. for(unsigned i = 0; i < m_sceneNoTriangles->mNumMeshes; ++i)
  717. {
  718. if(m_sceneNoTriangles->mMeshes[i]->mName == m_scene->mMeshes[meshIndex]->mName)
  719. {
  720. // Found
  721. proxy.m_meshIndex = i;
  722. break;
  723. }
  724. }
  725. if(proxy.m_meshIndex == 0xFFFFFFFF)
  726. {
  727. ERROR("Reflection proxy mesh not found");
  728. }
  729. proxy.m_transform = toAnkiMatrix(ainode->mTransformation);
  730. m_reflectionProxies.push_back(proxy);
  731. special = true;
  732. }
  733. else if(prop.first == "occluder" && prop.second == "true")
  734. {
  735. OccluderNode occluder;
  736. occluder.m_meshIndex = meshIndex;
  737. occluder.m_transform = toAnkiMatrix(ainode->mTransformation);
  738. m_occluders.push_back(occluder);
  739. special = true;
  740. }
  741. else if(prop.first == "collision_mesh")
  742. {
  743. collisionMesh = prop.second;
  744. special = false;
  745. }
  746. else if(prop.first.find("decal_") == 0)
  747. {
  748. DecalNode decal;
  749. for(const auto& pr : m_scene->mMeshes[meshIndex]->mProperties)
  750. {
  751. if(pr.first == "decal_diffuse_atlas")
  752. {
  753. decal.m_diffuseTextureAtlasFilename = pr.second;
  754. }
  755. else if(pr.first == "decal_diffuse_sub_texture")
  756. {
  757. decal.m_diffuseSubTextureName = pr.second;
  758. }
  759. else if(pr.first == "decal_diffuse_factor")
  760. {
  761. decal.m_factors[0] = std::stof(pr.second);
  762. }
  763. else if(pr.first == "decal_normal_roughness_atlas")
  764. {
  765. decal.m_specularRoughnessAtlasFilename = pr.second;
  766. }
  767. else if(pr.first == "decal_normal_roughness_sub_texture")
  768. {
  769. decal.m_specularRoughnessSubTextureName = pr.second;
  770. }
  771. else if(pr.first == "decal_normal_roughness_factor")
  772. {
  773. decal.m_factors[1] = std::stof(pr.second);
  774. }
  775. }
  776. if(decal.m_diffuseTextureAtlasFilename.empty() || decal.m_diffuseSubTextureName.empty())
  777. {
  778. ERROR("Missing decal information");
  779. }
  780. aiMatrix4x4 trf = toAnkiMatrix(ainode->mTransformation);
  781. decal.m_size = getNonUniformScale(trf);
  782. removeScale(trf);
  783. decal.m_transform = trf;
  784. m_decals.push_back(decal);
  785. special = true;
  786. break;
  787. }
  788. }
  789. if(isGiProbe)
  790. {
  791. m_giProbes.push_back(giProbe);
  792. }
  793. if(isParticleEmitter)
  794. {
  795. m_particleEmitters.push_back(particleEmitter);
  796. }
  797. if(special)
  798. {
  799. continue;
  800. }
  801. // Create new model
  802. Model mdl;
  803. mdl.m_meshIndex = meshIndex;
  804. mdl.m_materialIndex = mtlIndex;
  805. mdl.m_lod1MeshName = lod1MeshName;
  806. m_models.push_back(mdl);
  807. // Create new node
  808. Node node;
  809. node.m_modelIndex = uint32_t(m_models.size() - 1);
  810. node.m_transform = toAnkiMatrix(ainode->mTransformation);
  811. node.m_group = ainode->mGroup.C_Str();
  812. node.m_collisionMesh = collisionMesh;
  813. m_nodes.push_back(node);
  814. }
  815. // Go to children
  816. for(uint32_t i = 0; i < ainode->mNumChildren; i++)
  817. {
  818. visitNode(ainode->mChildren[i]);
  819. }
  820. }
  821. void Exporter::exportCollisionMesh(uint32_t meshIdx)
  822. {
  823. std::string name = getMeshName(getMeshAt(meshIdx));
  824. std::fstream file;
  825. file.open(m_outputDirectory + name + ".ankicl", std::ios::out);
  826. file << XML_HEADER << '\n';
  827. // Write collision mesh
  828. file << "<collisionShape>\n\t<type>staticMesh</type>\n\t<value>" << m_rpath << name
  829. << ".ankimesh</value>\n</collisionShape>\n";
  830. }
  831. void Exporter::exportAll()
  832. {
  833. LOGI("Exporting scene to %s", &m_outputDirectory[0]);
  834. //
  835. // Open scene file
  836. //
  837. m_sceneFile.open(m_outputDirectory + "scene.lua");
  838. std::ofstream& file = m_sceneFile;
  839. file << "local scene = getSceneGraph()\n"
  840. << "local events = getEventManager()\n"
  841. << "local rot\n"
  842. << "local node\n"
  843. << "local inst\n"
  844. << "local lcomp\n";
  845. //
  846. // Get all node/model data
  847. //
  848. visitNode(m_scene->mRootNode);
  849. //
  850. // Export collision meshes
  851. //
  852. for(auto n : m_staticCollisionNodes)
  853. {
  854. exportMesh(*m_scene->mMeshes[n.m_meshIndex], nullptr, 3);
  855. exportCollisionMesh(n.m_meshIndex);
  856. file << "\n";
  857. writeTransform(n.m_transform);
  858. std::string name = getMeshName(getMeshAt(n.m_meshIndex));
  859. std::string fname = m_rpath + name + ".ankicl";
  860. file << "node = scene:newStaticCollisionNode(\"" << name << "\", \"" << fname << "\", trf)\n";
  861. }
  862. //
  863. // Export particle emitters
  864. //
  865. int i = 0;
  866. for(const ParticleEmitter& p : m_particleEmitters)
  867. {
  868. std::string name = "particles" + std::to_string(i);
  869. file << "\nnode = scene:new" << (p.m_gpu ? "Gpu" : "") << "ParticleEmitterNode(\"" << name << "\", \""
  870. << p.m_filename << "\")\n";
  871. writeNodeTransform("node", p.m_transform);
  872. ++i;
  873. }
  874. //
  875. // Export refl probes
  876. //
  877. i = 0;
  878. for(const ReflectionProbe& probe : m_reflectionProbes)
  879. {
  880. std::string name = "reflprobe" + std::to_string(i);
  881. file << "\nnode = scene:newReflectionProbeNode(\"" << name << "\", Vec4.new(" << probe.m_aabbMin.x << ", "
  882. << probe.m_aabbMin.y << ", " << probe.m_aabbMin.z << ", 0), Vec4.new(" << probe.m_aabbMax.x << ", "
  883. << probe.m_aabbMax.y << ", " << probe.m_aabbMax.z << ", 0))\n";
  884. aiMatrix4x4 trf;
  885. aiMatrix4x4::Translation(probe.m_position, trf);
  886. writeNodeTransform("node", trf);
  887. ++i;
  888. }
  889. //
  890. // Export GI probes
  891. //
  892. i = 0;
  893. for(const GiProbe& probe : m_giProbes)
  894. {
  895. std::string name = "giprobe" + std::to_string(i);
  896. file << "\nnode = scene:newGlobalIlluminationProbeNode(\"" << name << "\")\n";
  897. file << "comp = node:getSceneNodeBase():getGlobalIlluminationProbeComponent()\n";
  898. file << "comp:setBoundingBox(Vec4.new(" << probe.m_aabbMin.x << ", " << probe.m_aabbMin.y << ", "
  899. << probe.m_aabbMin.z << ", 0), Vec4.new(" << probe.m_aabbMax.x << ", " << probe.m_aabbMax.y << ", "
  900. << probe.m_aabbMax.z << ", 0))\n";
  901. if(probe.m_fadeDistance >= 0.0f)
  902. {
  903. file << "comp:setFadeDistance(" << probe.m_fadeDistance << ")\n";
  904. }
  905. if(probe.m_cellSize > 0.0f)
  906. {
  907. file << "comp:setCellSize(" << probe.m_cellSize << ")\n";
  908. }
  909. aiMatrix4x4 trf;
  910. aiMatrix4x4::Translation(probe.m_position, trf);
  911. writeNodeTransform("node", trf);
  912. ++i;
  913. }
  914. //
  915. // Export proxies
  916. //
  917. i = 0;
  918. for(const ReflectionProxy& proxy : m_reflectionProxies)
  919. {
  920. const aiMesh& mesh = *m_sceneNoTriangles->mMeshes[proxy.m_meshIndex];
  921. exportMesh(mesh, nullptr, 4);
  922. std::string name = "reflproxy" + std::to_string(i);
  923. file << "\nnode = scene:newReflectionProxyNode(\"" << name << "\", \"" << m_rpath << mesh.mName.C_Str()
  924. << ".ankimesh\")\n";
  925. writeNodeTransform("node", proxy.m_transform);
  926. ++i;
  927. }
  928. //
  929. // Export occluders
  930. //
  931. i = 0;
  932. for(const OccluderNode& occluder : m_occluders)
  933. {
  934. const aiMesh& mesh = *m_scene->mMeshes[occluder.m_meshIndex];
  935. exportMesh(mesh, nullptr, 3);
  936. std::string name = "occluder" + std::to_string(i);
  937. file << "\nnode = scene:newOccluderNode(\"" << name << "\", \"" << m_rpath << mesh.mName.C_Str()
  938. << ".ankimesh\")\n";
  939. writeNodeTransform("node", occluder.m_transform);
  940. ++i;
  941. }
  942. //
  943. // Export decals
  944. //
  945. i = 0;
  946. for(const DecalNode& decal : m_decals)
  947. {
  948. std::string name = "decal" + std::to_string(i);
  949. file << "\nnode = scene:newDecalNode(\"" << name << "\")\n";
  950. writeNodeTransform("node", decal.m_transform);
  951. file << "decalc = node:getSceneNodeBase():getDecalComponent()\n";
  952. file << "decalc:setDiffuseDecal(\"" << decal.m_diffuseTextureAtlasFilename << "\", \""
  953. << decal.m_diffuseSubTextureName << "\", " << decal.m_factors[0] << ")\n";
  954. file << "decalc:updateShape(" << decal.m_size.x << ", " << decal.m_size.y << ", " << decal.m_size.z << ")\n";
  955. if(!decal.m_specularRoughnessAtlasFilename.empty())
  956. {
  957. file << "decalc:setSpecularRoughnessDecal(\"" << decal.m_specularRoughnessAtlasFilename << "\", \""
  958. << decal.m_specularRoughnessSubTextureName << "\", " << decal.m_factors[1] << ")\n";
  959. }
  960. ++i;
  961. }
  962. //
  963. // Export nodes and models.
  964. //
  965. for(uint32_t i = 0; i < m_nodes.size(); i++)
  966. {
  967. Node& node = m_nodes[i];
  968. Model& model = m_models[node.m_modelIndex];
  969. // TODO If static bake transform
  970. exportMesh(*m_scene->mMeshes[model.m_meshIndex], nullptr, 3);
  971. exportMaterial(*m_scene->mMaterials[model.m_materialIndex]);
  972. exportModel(model);
  973. std::string modelName = getModelName(model);
  974. std::string nodeName = modelName + node.m_group + std::to_string(i);
  975. // Write the main node
  976. file << "\nnode = scene:newModelNode(\"" << nodeName << "\", \"" << m_rpath << modelName << ".ankimdl\")\n";
  977. writeNodeTransform("node", node.m_transform);
  978. // Write the collision node
  979. if(!node.m_collisionMesh.empty())
  980. {
  981. unsigned i = 0;
  982. if(node.m_collisionMesh == "self")
  983. {
  984. i = model.m_meshIndex;
  985. }
  986. else
  987. {
  988. for(; i < m_scene->mNumMeshes; i++)
  989. {
  990. if(m_scene->mMeshes[i]->mName.C_Str() == node.m_collisionMesh)
  991. {
  992. break;
  993. }
  994. }
  995. }
  996. const bool found = i < m_scene->mNumMeshes;
  997. if(found)
  998. {
  999. exportCollisionMesh(i);
  1000. std::string fname = m_rpath + getMeshName(getMeshAt(i)) + ".ankicl";
  1001. file << "node = scene:newStaticCollisionNode(\"" << nodeName << "_cl\", \"" << fname << "\", trf)\n";
  1002. }
  1003. else
  1004. {
  1005. ERROR("Couldn't find the collision_mesh %s", node.m_collisionMesh.c_str());
  1006. }
  1007. }
  1008. }
  1009. //
  1010. // Lights
  1011. //
  1012. for(unsigned i = 0; i < m_scene->mNumLights; i++)
  1013. {
  1014. exportLight(*m_scene->mLights[i]);
  1015. }
  1016. //
  1017. // Animations
  1018. //
  1019. for(unsigned i = 0; i < m_scene->mNumAnimations; i++)
  1020. {
  1021. exportAnimation(*m_scene->mAnimations[i], i);
  1022. }
  1023. //
  1024. // Cameras
  1025. //
  1026. for(unsigned i = 0; i < m_scene->mNumCameras; i++)
  1027. {
  1028. exportCamera(*m_scene->mCameras[i]);
  1029. }
  1030. LOGI("Done exporting scene!");
  1031. }