JoinVerticesProcess.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /** @file Implementation of the post processing step to join identical vertices
  2. * for all imported meshes
  3. */
  4. #include <vector>
  5. #include <assert.h>
  6. #include "JoinVerticesProcess.h"
  7. #include "SpatialSort.h"
  8. #include "../include/aiPostProcess.h"
  9. #include "../include/aiMesh.h"
  10. #include "../include/aiScene.h"
  11. using namespace Assimp;
  12. // ------------------------------------------------------------------------------------------------
  13. // Constructor to be privately used by Importer
  14. JoinVerticesProcess::JoinVerticesProcess()
  15. {
  16. // nothing to do here
  17. }
  18. // ------------------------------------------------------------------------------------------------
  19. // Destructor, private as well
  20. JoinVerticesProcess::~JoinVerticesProcess()
  21. {
  22. // nothing to do here
  23. }
  24. // ------------------------------------------------------------------------------------------------
  25. // Returns whether the processing step is present in the given flag field.
  26. bool JoinVerticesProcess::IsActive( unsigned int pFlags) const
  27. {
  28. return (pFlags & aiProcess_JoinIdenticalVertices) != 0;
  29. }
  30. // ------------------------------------------------------------------------------------------------
  31. // Executes the post processing step on the given imported data.
  32. void JoinVerticesProcess::Execute( aiScene* pScene)
  33. {
  34. for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
  35. ProcessMesh( pScene->mMeshes[a]);
  36. }
  37. // ------------------------------------------------------------------------------------------------
  38. // Unites identical vertices in the given mesh
  39. void JoinVerticesProcess::ProcessMesh( aiMesh* pMesh)
  40. {
  41. // helper structure to hold all the data a single vertex can possibly have
  42. typedef struct Vertex vertex;
  43. struct Vertex
  44. {
  45. aiVector3D mPosition;
  46. aiVector3D mNormal;
  47. aiVector3D mTangent, mBitangent;
  48. aiColor4D mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
  49. aiVector3D mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
  50. };
  51. std::vector<Vertex> uniqueVertices;
  52. uniqueVertices.reserve( pMesh->mNumVertices);
  53. // For each vertex the index of the vertex it was replaced by.
  54. std::vector<unsigned int> replaceIndex( pMesh->mNumVertices, 0xffffffff);
  55. // for each vertex whether it was replaced by an existing unique vertex (true) or a new vertex was created for it (false)
  56. std::vector<bool> isVertexUnique( pMesh->mNumVertices, false);
  57. // calculate the position bounds so we have a reliable epsilon to check position differences against
  58. aiVector3D minVec( 1e10f, 1e10f, 1e10f), maxVec( -1e10f, -1e10f, -1e10f);
  59. for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
  60. {
  61. minVec.x = std::min( minVec.x, pMesh->mVertices[a].x);
  62. minVec.y = std::min( minVec.y, pMesh->mVertices[a].y);
  63. minVec.z = std::min( minVec.z, pMesh->mVertices[a].z);
  64. maxVec.x = std::max( maxVec.x, pMesh->mVertices[a].x);
  65. maxVec.y = std::max( maxVec.y, pMesh->mVertices[a].y);
  66. maxVec.z = std::max( maxVec.z, pMesh->mVertices[a].z);
  67. }
  68. // squared because we check against squared length of the vector difference
  69. const float epsilon = 1e-5f;
  70. const float posEpsilon = (maxVec - minVec).Length() * epsilon;
  71. const float squareEpsilon = epsilon * epsilon;
  72. // a little helper to find locally close vertices faster
  73. SpatialSort vertexFinder( pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
  74. std::vector<unsigned int> verticesFound;
  75. // now check each vertex if it brings something new to the table
  76. for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
  77. {
  78. // collect the vertex data
  79. Vertex v;
  80. v.mPosition = pMesh->mVertices[a];
  81. v.mNormal = (pMesh->mNormals != NULL) ? pMesh->mNormals[a] : aiVector3D( 0, 0, 0);
  82. v.mTangent = (pMesh->mTangents != NULL) ? pMesh->mTangents[a] : aiVector3D( 0, 0, 0);
  83. v.mBitangent = (pMesh->mBitangents != NULL) ? pMesh->mBitangents[a] : aiVector3D( 0, 0, 0);
  84. for( unsigned int b = 0; b < AI_MAX_NUMBER_OF_COLOR_SETS; b++)
  85. v.mColors[b] = (pMesh->mColors[b] != NULL) ? pMesh->mColors[b][a] : aiColor4D( 0, 0, 0, 0);
  86. for( unsigned int b = 0; b < AI_MAX_NUMBER_OF_TEXTURECOORDS; b++)
  87. v.mTexCoords[b] = (pMesh->mTextureCoords[b] != NULL) ? pMesh->mTextureCoords[b][a] : aiVector3D( 0, 0, 0);
  88. // collect all vertices that are close enough to the given position
  89. vertexFinder.FindPositions( v.mPosition, posEpsilon, verticesFound);
  90. unsigned int matchIndex = 0xffffffff;
  91. // check all unique vertices close to the position if this vertex is already present among them
  92. for( unsigned int b = 0; b < verticesFound.size(); b++)
  93. {
  94. unsigned int vidx = verticesFound[b];
  95. unsigned int uidx = replaceIndex[ vidx];
  96. if( uidx == 0xffffffff || !isVertexUnique[ vidx])
  97. continue;
  98. const Vertex& uv = uniqueVertices[ uidx];
  99. // Position mismatch is impossible - the vertex finder already discarded all non-matching positions
  100. // We just test the other attributes even if they're not present in the mesh.
  101. // In this case they're initialized to 0 so the comparision succeeds.
  102. // By this method the non-present attributes are effectively ignored in the comparision.
  103. if( (uv.mNormal - v.mNormal).SquareLength() > squareEpsilon)
  104. continue;
  105. if( (uv.mTangent - v.mTangent).SquareLength() > squareEpsilon)
  106. continue;
  107. if( (uv.mBitangent - v.mBitangent).SquareLength() > squareEpsilon)
  108. continue;
  109. // manually unrolled because continue wouldn't work as desired in an inner loop
  110. assert( AI_MAX_NUMBER_OF_COLOR_SETS == 4);
  111. if( GetColorDifference( uv.mColors[0], v.mColors[0]) > squareEpsilon)
  112. continue;
  113. if( GetColorDifference( uv.mColors[1], v.mColors[1]) > squareEpsilon)
  114. continue;
  115. if( GetColorDifference( uv.mColors[2], v.mColors[2]) > squareEpsilon)
  116. continue;
  117. if( GetColorDifference( uv.mColors[3], v.mColors[3]) > squareEpsilon)
  118. continue;
  119. // texture coord matching manually unrolled as well
  120. assert( AI_MAX_NUMBER_OF_TEXTURECOORDS == 4);
  121. if( (uv.mTexCoords[0] - v.mTexCoords[0]).SquareLength() > squareEpsilon)
  122. continue;
  123. if( (uv.mTexCoords[1] - v.mTexCoords[1]).SquareLength() > squareEpsilon)
  124. continue;
  125. if( (uv.mTexCoords[2] - v.mTexCoords[2]).SquareLength() > squareEpsilon)
  126. continue;
  127. if( (uv.mTexCoords[3] - v.mTexCoords[3]).SquareLength() > squareEpsilon)
  128. continue;
  129. // we're still here -> this vertex perfectly matches our given vertex
  130. matchIndex = uidx;
  131. break;
  132. }
  133. // found a replacement vertex among the uniques?
  134. if( matchIndex != 0xffffffff)
  135. {
  136. // store where to found the matching unique vertex
  137. replaceIndex[a] = matchIndex;
  138. isVertexUnique[a] = false;
  139. } else
  140. {
  141. // no unique vertex matches it upto now -> so add it
  142. replaceIndex[a] = uniqueVertices.size();
  143. uniqueVertices.push_back( v);
  144. isVertexUnique[a] = true;
  145. }
  146. }
  147. // replace vertex data with the unique data sets
  148. pMesh->mNumVertices = uniqueVertices.size();
  149. // Position
  150. delete [] pMesh->mVertices;
  151. pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
  152. for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
  153. pMesh->mVertices[a] = uniqueVertices[a].mPosition;
  154. // Normals, if present
  155. if( pMesh->mNormals)
  156. {
  157. delete [] pMesh->mNormals;
  158. pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  159. for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
  160. pMesh->mNormals[a] = uniqueVertices[a].mNormal;
  161. }
  162. // Tangents, if present
  163. if( pMesh->mTangents)
  164. {
  165. delete [] pMesh->mTangents;
  166. pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
  167. for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
  168. pMesh->mTangents[a] = uniqueVertices[a].mTangent;
  169. }
  170. // Bitangents as well
  171. if( pMesh->mBitangents)
  172. {
  173. delete [] pMesh->mBitangents;
  174. pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
  175. for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
  176. pMesh->mBitangents[a] = uniqueVertices[a].mBitangent;
  177. }
  178. // Vertex colors
  179. for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++)
  180. {
  181. if( !pMesh->mColors[a])
  182. continue;
  183. delete [] pMesh->mColors[a];
  184. pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices];
  185. for( unsigned int b = 0; b < pMesh->mNumVertices; b++)
  186. pMesh->mColors[a][b] = uniqueVertices[b].mColors[a];
  187. }
  188. // Texture coords
  189. for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)
  190. {
  191. if( !pMesh->mTextureCoords[a])
  192. continue;
  193. delete [] pMesh->mTextureCoords[a];
  194. pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
  195. for( unsigned int b = 0; b < pMesh->mNumVertices; b++)
  196. pMesh->mTextureCoords[a][b] = uniqueVertices[b].mTexCoords[a];
  197. }
  198. // adjust the indices in all faces
  199. for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
  200. {
  201. aiFace& face = pMesh->mFaces[a];
  202. for( unsigned int b = 0; b < face.mNumIndices; b++)
  203. {
  204. const size_t index = face.mIndices[b];
  205. face.mIndices[b] = replaceIndex[face.mIndices[b]];
  206. }
  207. }
  208. // adjust bone vertex weights.
  209. for( unsigned int a = 0; a < pMesh->mNumBones; a++)
  210. {
  211. aiBone* bone = pMesh->mBones[a];
  212. std::vector<aiVertexWeight> newWeights;
  213. newWeights.reserve( bone->mNumWeights);
  214. for( unsigned int b = 0; b < bone->mNumWeights; b++)
  215. {
  216. const aiVertexWeight& ow = bone->mWeights[b];
  217. // if the vertex is a unique one, translate it
  218. if( isVertexUnique[ow.mVertexId])
  219. {
  220. aiVertexWeight nw;
  221. nw.mVertexId = replaceIndex[ow.mVertexId];
  222. nw.mWeight = ow.mWeight;
  223. newWeights.push_back( nw);
  224. }
  225. }
  226. // there should be some. At least I think there should be some
  227. assert( newWeights.size() > 0);
  228. // kill the old and replace them with the translated weights
  229. delete [] bone->mWeights;
  230. bone->mNumWeights = newWeights.size();
  231. bone->mWeights = new aiVertexWeight[bone->mNumWeights];
  232. memcpy( bone->mWeights, &newWeights[0], bone->mNumWeights * sizeof( aiVertexWeight));
  233. }
  234. }