CalcTangentsProcess.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /** @file Implementation of the post processing step to calculate tangents and bitangents
  2. * for all imported meshes
  3. */
  4. #include <vector>
  5. #include <assert.h>
  6. #include "CalcTangentsProcess.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. CalcTangentsProcess::CalcTangentsProcess()
  15. {
  16. // nothing to do here
  17. }
  18. // ------------------------------------------------------------------------------------------------
  19. // Destructor, private as well
  20. CalcTangentsProcess::~CalcTangentsProcess()
  21. {
  22. // nothing to do here
  23. }
  24. // ------------------------------------------------------------------------------------------------
  25. // Returns whether the processing step is present in the given flag field.
  26. bool CalcTangentsProcess::IsActive( unsigned int pFlags) const
  27. {
  28. return (pFlags & aiProcess_CalcTangentSpace) != 0;
  29. }
  30. // ------------------------------------------------------------------------------------------------
  31. // Executes the post processing step on the given imported data.
  32. void CalcTangentsProcess::Execute( aiScene* pScene)
  33. {
  34. for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
  35. ProcessMesh( pScene->mMeshes[a]);
  36. }
  37. // ------------------------------------------------------------------------------------------------
  38. // Calculates tangents and bitangents for the given mesh
  39. void CalcTangentsProcess::ProcessMesh( aiMesh* pMesh)
  40. {
  41. // we assume that the mesh is still in the verbose vertex format where each face has its own set
  42. // of vertices and no vertices are shared between faces. Sadly I don't know any quick test to
  43. // assert() it here.
  44. //assert( must be verbose, dammit);
  45. // what we can check, though, is if the mesh has normals and texture coord. That's a requirement
  46. if( pMesh->mNormals == NULL || pMesh->mTextureCoords[0] == NULL)
  47. return;
  48. // calculate the position bounds so we have a reliable epsilon to check position differences against
  49. aiVector3D minVec( 1e10f, 1e10f, 1e10f), maxVec( -1e10f, -1e10f, -1e10f);
  50. for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
  51. {
  52. minVec.x = std::min( minVec.x, pMesh->mVertices[a].x);
  53. minVec.y = std::min( minVec.y, pMesh->mVertices[a].y);
  54. minVec.z = std::min( minVec.z, pMesh->mVertices[a].z);
  55. maxVec.x = std::max( maxVec.x, pMesh->mVertices[a].x);
  56. maxVec.y = std::max( maxVec.y, pMesh->mVertices[a].y);
  57. maxVec.z = std::max( maxVec.z, pMesh->mVertices[a].z);
  58. }
  59. // calculate epsilons border
  60. const float epsilon = 1e-5f;
  61. const float posEpsilon = (maxVec - minVec).Length() * epsilon;
  62. const float angleEpsilon = 0.9999f;
  63. // create space for the tangents and bitangents
  64. pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
  65. pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
  66. const aiVector3D* meshPos = pMesh->mVertices;
  67. const aiVector3D* meshNorm = pMesh->mNormals;
  68. const aiVector3D* meshTex = pMesh->mTextureCoords[0];
  69. aiVector3D* meshTang = pMesh->mTangents;
  70. aiVector3D* meshBitang = pMesh->mBitangents;
  71. // calculate the tangent and bitangent for every face
  72. for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
  73. {
  74. const aiFace& face = pMesh->mFaces[a];
  75. // triangle or polygon... we always use only the first three indices. A polygon
  76. // is supposed to be planar anyways....
  77. // FIXME: (thom) create correct calculation for multi-vertex polygons maybe?
  78. const unsigned int p0 = face.mIndices[0], p1 = face.mIndices[1], p2 = face.mIndices[2];
  79. // position differences p1->p2 and p1->p3
  80. aiVector3D v = meshPos[p1] - meshPos[p0], w = meshPos[p2] - meshPos[p0];
  81. // texture offset p1->p2 and p1->p3
  82. float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y;
  83. float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
  84. float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
  85. // tangent points in the direction where to positive X axis of the texture coords would point in model space
  86. // bitangents points along the positive Y axis of the texture coords, respectively
  87. aiVector3D tangent, bitangent;
  88. tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
  89. tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
  90. tangent.z = (w.z * sy - v.z * ty) * dirCorrection;
  91. bitangent.x = (w.x * sx - v.x * tx) * dirCorrection;
  92. bitangent.y = (w.y * sx - v.y * tx) * dirCorrection;
  93. bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
  94. // store for every vertex of that face
  95. for( unsigned int b = 0; b < face.mNumIndices; b++)
  96. {
  97. unsigned int p = face.mIndices[b];
  98. // project tangent and bitangent into the plane formed by the vertex' normal
  99. aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
  100. aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
  101. localTangent.Normalize(); localBitangent.Normalize();
  102. // and write it into the mesh.
  103. meshTang[p] = localTangent;
  104. meshBitang[p] = localBitangent;
  105. }
  106. }
  107. // create a helper to quickly find locally close vertices among the vertex array
  108. SpatialSort vertexFinder( meshPos, pMesh->mNumVertices, sizeof( aiVector3D));
  109. std::vector<unsigned int> verticesFound;
  110. // in the second pass we now smooth out all tangents and bitangents at the same local position
  111. // if they are not too far off.
  112. std::vector<bool> vertexDone( pMesh->mNumVertices, false);
  113. for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
  114. {
  115. if( vertexDone[a])
  116. continue;
  117. const aiVector3D& origPos = pMesh->mVertices[a];
  118. const aiVector3D& origNorm = pMesh->mNormals[a];
  119. const aiVector3D& origTang = pMesh->mTangents[a];
  120. const aiVector3D& origBitang = pMesh->mBitangents[a];
  121. std::vector<unsigned int> closeVertices;
  122. closeVertices.push_back( a);
  123. // find all vertices close to that position
  124. vertexFinder.FindPositions( origPos, posEpsilon, verticesFound);
  125. // look among them for other vertices sharing the same normal and a close-enough tangent/bitangent
  126. static const float MAX_DIFF_ANGLE = 0.701f;
  127. for( unsigned int b = 0; b < verticesFound.size(); b++)
  128. {
  129. unsigned int idx = verticesFound[b];
  130. if( vertexDone[idx])
  131. continue;
  132. if( meshNorm[idx] * origNorm < angleEpsilon)
  133. continue;
  134. if( meshTang[idx] * origTang < MAX_DIFF_ANGLE)
  135. continue;
  136. if( meshBitang[idx] * origBitang < MAX_DIFF_ANGLE)
  137. continue;
  138. // it's similar enough -> add it to the smoothing group
  139. closeVertices.push_back( idx);
  140. vertexDone[idx] = true;
  141. }
  142. // smooth the tangents and bitangents of all vertices that were found to be close enough
  143. aiVector3D smoothTangent( 0, 0, 0), smoothBitangent( 0, 0, 0);
  144. for( unsigned int b = 0; b < closeVertices.size(); b++)
  145. {
  146. smoothTangent += meshTang[ closeVertices[b] ];
  147. smoothBitangent += meshBitang[ closeVertices[b] ];
  148. }
  149. smoothTangent.Normalize();
  150. smoothBitangent.Normalize();
  151. // and write it back into all affected tangents
  152. for( unsigned int b = 0; b < closeVertices.size(); b++)
  153. {
  154. meshTang[ closeVertices[b] ] = smoothTangent;
  155. meshBitang[ closeVertices[b] ] = smoothBitangent;
  156. }
  157. }
  158. }