mesh_splitter.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. Assimp2Json
  3. Copyright (c) 2011, Alexander C. Gessler
  4. Licensed under a 3-clause BSD license. See the LICENSE file for more information.
  5. */
  6. #include "mesh_splitter.h"
  7. #include <assimp/scene.h>
  8. // ----------------------------------------------------------------------------
  9. // Note: this is largely based on assimp's SplitLargeMeshes_Vertex process.
  10. // it is refactored and the coding style is slightly improved, though.
  11. // ----------------------------------------------------------------------------
  12. // ------------------------------------------------------------------------------------------------
  13. // Executes the post processing step on the given imported data.
  14. void MeshSplitter::Execute( aiScene* pScene) {
  15. std::vector<std::pair<aiMesh*, unsigned int> > source_mesh_map;
  16. for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  17. SplitMesh(a, pScene->mMeshes[a],source_mesh_map);
  18. }
  19. const unsigned int size = static_cast<unsigned int>(source_mesh_map.size());
  20. if (size != pScene->mNumMeshes) {
  21. // it seems something has been split. rebuild the mesh list
  22. delete[] pScene->mMeshes;
  23. pScene->mNumMeshes = size;
  24. pScene->mMeshes = new aiMesh*[size]();
  25. for (unsigned int i = 0; i < size;++i) {
  26. pScene->mMeshes[i] = source_mesh_map[i].first;
  27. }
  28. // now we need to update all nodes
  29. UpdateNode(pScene->mRootNode,source_mesh_map);
  30. }
  31. }
  32. // ------------------------------------------------------------------------------------------------
  33. void MeshSplitter::UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh*, unsigned int> >& source_mesh_map) {
  34. // TODO: should better use std::(multi)set for source_mesh_map.
  35. // for every index in out list build a new entry
  36. std::vector<unsigned int> aiEntries;
  37. aiEntries.reserve(pcNode->mNumMeshes + 1);
  38. for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) {
  39. for (unsigned int a = 0, end = static_cast<unsigned int>(source_mesh_map.size()); a < end;++a) {
  40. if (source_mesh_map[a].second == pcNode->mMeshes[i]) {
  41. aiEntries.push_back(a);
  42. }
  43. }
  44. }
  45. // now build the new list
  46. delete pcNode->mMeshes;
  47. pcNode->mNumMeshes = static_cast<unsigned int>(aiEntries.size());
  48. pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
  49. for (unsigned int b = 0; b < pcNode->mNumMeshes;++b) {
  50. pcNode->mMeshes[b] = aiEntries[b];
  51. }
  52. // recursively update children
  53. for (unsigned int i = 0, end = pcNode->mNumChildren; i < end;++i) {
  54. UpdateNode ( pcNode->mChildren[i], source_mesh_map );
  55. }
  56. return;
  57. }
  58. #define WAS_NOT_COPIED 0xffffffff
  59. typedef std::pair <unsigned int,float> PerVertexWeight;
  60. typedef std::vector <PerVertexWeight> VertexWeightTable;
  61. // ------------------------------------------------------------------------------------------------
  62. VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh) {
  63. if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) {
  64. return nullptr;
  65. }
  66. VertexWeightTable* const avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices];
  67. for (unsigned int i = 0; i < pMesh->mNumBones;++i) {
  68. aiBone* bone = pMesh->mBones[i];
  69. for (unsigned int a = 0; a < bone->mNumWeights;++a) {
  70. const aiVertexWeight& weight = bone->mWeights[a];
  71. avPerVertexWeights[weight.mVertexId].push_back( std::make_pair(i,weight.mWeight) );
  72. }
  73. }
  74. return avPerVertexWeights;
  75. }
  76. // ------------------------------------------------------------------------------------------------
  77. void MeshSplitter :: SplitMesh(unsigned int a, aiMesh* in_mesh, std::vector<std::pair<aiMesh*, unsigned int> >& source_mesh_map) {
  78. // TODO: should better use std::(multi)set for source_mesh_map.
  79. if (in_mesh->mNumVertices <= LIMIT) {
  80. source_mesh_map.push_back(std::make_pair(in_mesh,a));
  81. return;
  82. }
  83. // build a per-vertex weight list if necessary
  84. VertexWeightTable* avPerVertexWeights = ComputeVertexBoneWeightTable(in_mesh);
  85. // we need to split this mesh into sub meshes. Estimate submesh size
  86. const unsigned int sub_meshes = (in_mesh->mNumVertices / LIMIT) + 1;
  87. // create a std::vector<unsigned int> to remember which vertices have already
  88. // been copied and to which position (i.e. output index)
  89. std::vector<unsigned int> was_copied_to;
  90. was_copied_to.resize(in_mesh->mNumVertices,WAS_NOT_COPIED);
  91. // Try to find a good estimate for the number of output faces
  92. // per mesh. Add 12.5% as buffer
  93. unsigned int size_estimated = in_mesh->mNumFaces / sub_meshes;
  94. size_estimated += size_estimated / 8;
  95. // now generate all submeshes
  96. unsigned int base = 0;
  97. while (true) {
  98. const unsigned int out_vertex_index = LIMIT;
  99. aiMesh* out_mesh = new aiMesh();
  100. out_mesh->mNumVertices = 0;
  101. out_mesh->mMaterialIndex = in_mesh->mMaterialIndex;
  102. // the name carries the adjacency information between the meshes
  103. out_mesh->mName = in_mesh->mName;
  104. typedef std::vector<aiVertexWeight> BoneWeightList;
  105. if (in_mesh->HasBones()) {
  106. out_mesh->mBones = new aiBone*[in_mesh->mNumBones]();
  107. }
  108. // clear the temporary helper array
  109. if (base) {
  110. std::fill(was_copied_to.begin(), was_copied_to.end(), WAS_NOT_COPIED);
  111. }
  112. std::vector<aiFace> vFaces;
  113. // reserve enough storage for most cases
  114. if (in_mesh->HasPositions()) {
  115. out_mesh->mVertices = new aiVector3D[out_vertex_index];
  116. }
  117. if (in_mesh->HasNormals()) {
  118. out_mesh->mNormals = new aiVector3D[out_vertex_index];
  119. }
  120. if (in_mesh->HasTangentsAndBitangents()) {
  121. out_mesh->mTangents = new aiVector3D[out_vertex_index];
  122. out_mesh->mBitangents = new aiVector3D[out_vertex_index];
  123. }
  124. for (unsigned int c = 0; in_mesh->HasVertexColors(c);++c) {
  125. out_mesh->mColors[c] = new aiColor4D[out_vertex_index];
  126. }
  127. for (unsigned int c = 0; in_mesh->HasTextureCoords(c);++c) {
  128. out_mesh->mNumUVComponents[c] = in_mesh->mNumUVComponents[c];
  129. out_mesh->mTextureCoords[c] = new aiVector3D[out_vertex_index];
  130. }
  131. vFaces.reserve(size_estimated);
  132. // (we will also need to copy the array of indices)
  133. while (base < in_mesh->mNumFaces) {
  134. const unsigned int iNumIndices = in_mesh->mFaces[base].mNumIndices;
  135. // doesn't catch degenerates but is quite fast
  136. unsigned int iNeed = 0;
  137. for (unsigned int v = 0; v < iNumIndices;++v) {
  138. unsigned int index = in_mesh->mFaces[base].mIndices[v];
  139. // check whether we do already have this vertex
  140. if (WAS_NOT_COPIED == was_copied_to[index]) {
  141. iNeed++;
  142. }
  143. }
  144. if (out_mesh->mNumVertices + iNeed > out_vertex_index) {
  145. // don't use this face
  146. break;
  147. }
  148. vFaces.push_back(aiFace());
  149. aiFace& rFace = vFaces.back();
  150. // setup face type and number of indices
  151. rFace.mNumIndices = iNumIndices;
  152. rFace.mIndices = new unsigned int[iNumIndices];
  153. // need to update the output primitive types
  154. switch (rFace.mNumIndices)
  155. {
  156. case 1:
  157. out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  158. break;
  159. case 2:
  160. out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  161. break;
  162. case 3:
  163. out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  164. break;
  165. default:
  166. out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  167. }
  168. // and copy the contents of the old array, offset them by current base
  169. for (unsigned int v = 0; v < iNumIndices;++v) {
  170. const unsigned int index = in_mesh->mFaces[base].mIndices[v];
  171. // check whether we do already have this vertex
  172. if (WAS_NOT_COPIED != was_copied_to[index]) {
  173. rFace.mIndices[v] = was_copied_to[index];
  174. continue;
  175. }
  176. // copy positions
  177. out_mesh->mVertices[out_mesh->mNumVertices] = (in_mesh->mVertices[index]);
  178. // copy normals
  179. if (in_mesh->HasNormals()) {
  180. out_mesh->mNormals[out_mesh->mNumVertices] = (in_mesh->mNormals[index]);
  181. }
  182. // copy tangents/bi-tangents
  183. if (in_mesh->HasTangentsAndBitangents()) {
  184. out_mesh->mTangents[out_mesh->mNumVertices] = (in_mesh->mTangents[index]);
  185. out_mesh->mBitangents[out_mesh->mNumVertices] = (in_mesh->mBitangents[index]);
  186. }
  187. // texture coordinates
  188. for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
  189. if (in_mesh->HasTextureCoords( c)) {
  190. out_mesh->mTextureCoords[c][out_mesh->mNumVertices] = in_mesh->mTextureCoords[c][index];
  191. }
  192. }
  193. // vertex colors
  194. for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) {
  195. if (in_mesh->HasVertexColors( c)) {
  196. out_mesh->mColors[c][out_mesh->mNumVertices] = in_mesh->mColors[c][index];
  197. }
  198. }
  199. // check whether we have bone weights assigned to this vertex
  200. rFace.mIndices[v] = out_mesh->mNumVertices;
  201. if (avPerVertexWeights) {
  202. VertexWeightTable& table = avPerVertexWeights[ out_mesh->mNumVertices ];
  203. for (VertexWeightTable::const_iterator iter = table.begin(), end = table.end(); iter != end;++iter) {
  204. // allocate the bone weight array if necessary and store it in the mBones field (HACK!)
  205. BoneWeightList* weight_list = reinterpret_cast<BoneWeightList*>(out_mesh->mBones[(*iter).first]);
  206. if (!weight_list) {
  207. weight_list = new BoneWeightList();
  208. out_mesh->mBones[(*iter).first] = reinterpret_cast<aiBone*>(weight_list);
  209. }
  210. weight_list->push_back(aiVertexWeight(out_mesh->mNumVertices,(*iter).second));
  211. }
  212. }
  213. was_copied_to[index] = out_mesh->mNumVertices;
  214. out_mesh->mNumVertices++;
  215. }
  216. base++;
  217. if(out_mesh->mNumVertices == out_vertex_index) {
  218. // break here. The face is only added if it was complete
  219. break;
  220. }
  221. }
  222. // check which bones we'll need to create for this submesh
  223. if (in_mesh->HasBones()) {
  224. aiBone** ppCurrent = out_mesh->mBones;
  225. for (unsigned int k = 0; k < in_mesh->mNumBones;++k) {
  226. // check whether the bone exists
  227. BoneWeightList* const weight_list = reinterpret_cast<BoneWeightList*>(out_mesh->mBones[k]);
  228. if (weight_list) {
  229. const aiBone* const bone_in = in_mesh->mBones[k];
  230. aiBone* const bone_out = new aiBone();
  231. *ppCurrent++ = bone_out;
  232. bone_out->mName = aiString(bone_in->mName);
  233. bone_out->mOffsetMatrix =bone_in->mOffsetMatrix;
  234. bone_out->mNumWeights = (unsigned int)weight_list->size();
  235. bone_out->mWeights = new aiVertexWeight[bone_out->mNumWeights];
  236. // copy the vertex weights
  237. ::memcpy(bone_out->mWeights, &(*weight_list)[0],bone_out->mNumWeights * sizeof(aiVertexWeight));
  238. delete weight_list;
  239. out_mesh->mNumBones++;
  240. }
  241. }
  242. }
  243. // copy the face list to the mesh
  244. out_mesh->mFaces = new aiFace[vFaces.size()];
  245. out_mesh->mNumFaces = (unsigned int)vFaces.size();
  246. for (unsigned int p = 0; p < out_mesh->mNumFaces;++p) {
  247. out_mesh->mFaces[p] = vFaces[p];
  248. }
  249. // add the newly created mesh to the list
  250. source_mesh_map.push_back(std::make_pair(out_mesh,a));
  251. if (base == in_mesh->mNumFaces) {
  252. break;
  253. }
  254. }
  255. // delete the per-vertex weight list again
  256. delete[] avPerVertexWeights;
  257. // now delete the old mesh data
  258. delete in_mesh;
  259. }