mesh_splitter.cpp 11 KB

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