BVB Source Codes

CRYENGINE Show TangentSpaceCalculation.cpp Source code

Return Download CRYENGINE: download TangentSpaceCalculation.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include "TangentSpaceCalculation.h"
  5. #include "../../SDKs/TangentBasisComputation/mikkelsen/mikktspace.h"
  6.  
  7. struct SMikkVertex
  8. {
  9.         Vec3 pos, norm, tang, bitang;
  10.         Vec2 magST;
  11.         Vec2 texc;
  12. };
  13.  
  14. struct SMikkFace
  15. {
  16.         int vertexOffset;
  17.         int nrOriginalFace;
  18. };
  19.  
  20. struct SMikkMesh
  21. {
  22.         std::vector<SMikkVertex> mikkVerts;
  23.         std::vector<SMikkFace>   mikkFaces;
  24.         int                      mikkNumFaces;
  25. };
  26.  
  27. CTangentSpaceCalculation::CBase33::CBase33()
  28. {
  29. }
  30.  
  31. CTangentSpaceCalculation::CBase33::CBase33(const Vec3& Uval, const Vec3& Vval, const Vec3& Nval)
  32. {
  33.         u = Uval;
  34.         v = Vval;
  35.         n = Nval;
  36. }
  37.  
  38. bool CTangentSpaceCalculation::CVec3PredicateLess::operator()(const Vec3& first, const Vec3& second) const
  39. {
  40.         if (first.x < second.x)
  41.                 return true;
  42.  
  43.         if (first.x > second.x)
  44.                 return false;
  45.  
  46.         if (first.y < second.y)
  47.                 return true;
  48.  
  49.         if (first.y > second.y)
  50.                 return false;
  51.  
  52.         return (first.z < second.z);
  53. }
  54.  
  55. bool CTangentSpaceCalculation::CBase33PredicateLess::operator()(const CBase33& first, const CBase33& second) const
  56. {
  57.         if (first.n.x < second.n.x)
  58.                 return true;
  59.  
  60.         if (first.n.x > second.n.x)
  61.                 return false;
  62.  
  63.         if (first.n.y < second.n.y)
  64.                 return true;
  65.  
  66.         if (first.n.y > second.n.y)
  67.                 return false;
  68.  
  69.         if (first.n.z < second.n.z)
  70.                 return true;
  71.  
  72.         if (first.n.z > second.n.z)
  73.                 return false;
  74.  
  75.         if (first.u.x < second.u.x)
  76.                 return true;
  77.  
  78.         if (first.u.x > second.u.x)
  79.                 return false;
  80.  
  81.         if (first.u.y < second.u.y)
  82.                 return true;
  83.  
  84.         if (first.u.y > second.u.y)
  85.                 return false;
  86.  
  87.         if (first.u.z < second.u.z)
  88.                 return true;
  89.  
  90.         if (first.u.z > second.u.z)
  91.                 return false;
  92.  
  93.         if (first.v.x < second.v.x)
  94.                 return true;
  95.  
  96.         if (first.v.x > second.v.x)
  97.                 return false;
  98.  
  99.         if (first.v.y < second.v.y)
  100.                 return true;
  101.  
  102.         if (first.v.y > second.v.y)
  103.                 return false;
  104.  
  105.         return first.v.z < second.v.z;
  106. }
  107.  
  108. bool CTangentSpaceCalculation::CBaseIndexOrder::operator()(const CBaseIndex& a, const CBaseIndex& b) const
  109. {
  110.         // first sort by position
  111.         if (a.m_posIndex < b.m_posIndex) return true;
  112.         if (a.m_posIndex > b.m_posIndex) return false;
  113.  
  114.         // then by normal
  115.         if (a.m_normIndex < b.m_normIndex) return true;
  116.         if (a.m_normIndex > b.m_normIndex) return false;
  117.  
  118.         return false;
  119. }
  120.  
  121. float CTangentSpaceCalculation::CalcAngleBetween(const Vec3& invA, const Vec3& invB)
  122. {
  123.         double LengthQ = sqrt(invA.len2() * invB.len2());
  124.  
  125.         // to prevent division by zero
  126.         if (LengthQ < 0.00000001)
  127.                 LengthQ = 0.00000001;
  128.  
  129.         double f = invA.Dot(invB) / LengthQ;
  130.  
  131.         // cosf is not available on every platform
  132.         float fRet = (float)acos_tpl(f);
  133.  
  134.         return fRet;
  135. }
  136.  
  137. void CTangentSpaceCalculation::DebugMesh(const ITriangleInputProxy& proxy) const
  138. {
  139.         uint32 dwTriCount = proxy.GetTriangleCount();
  140.  
  141.         // search for polygons that use the same indices (input data problems)
  142.         for (uint32 a = 0; a < dwTriCount; a++)
  143.         {
  144.                 uint32 dwAPos[3], dwANorm[3], dwAUV[3];
  145.  
  146.                 proxy.GetTriangleIndices(a, dwAPos, dwANorm, dwAUV);
  147.  
  148.                 for (uint32 b = a + 1; b < dwTriCount; b++)
  149.                 {
  150.                         uint32 dwBPos[3], dwBNorm[3], dwBUV[3];
  151.  
  152.                         proxy.GetTriangleIndices(b, dwBPos, dwBNorm, dwBUV);
  153.  
  154.                         assert(!(dwAPos[0] == dwBPos[0] && dwAPos[1] == dwBPos[1] && dwAPos[2] == dwBPos[2]));
  155.                         assert(!(dwAPos[1] == dwBPos[0] && dwAPos[2] == dwBPos[1] && dwAPos[0] == dwBPos[2]));
  156.                         assert(!(dwAPos[2] == dwBPos[0] && dwAPos[0] == dwBPos[1] && dwAPos[1] == dwBPos[2]));
  157.  
  158.                         assert(!(dwAPos[1] == dwBPos[0] && dwAPos[0] == dwBPos[1] && dwAPos[2] == dwBPos[2]));
  159.                         assert(!(dwAPos[2] == dwBPos[0] && dwAPos[1] == dwBPos[1] && dwAPos[0] == dwBPos[2]));
  160.                         assert(!(dwAPos[0] == dwBPos[0] && dwAPos[2] == dwBPos[1] && dwAPos[1] == dwBPos[2]));
  161.                 }
  162.         }
  163. }
  164.  
  165. Vec3 CTangentSpaceCalculation::Rotate(const Vec3& vFrom, const Vec3& vTo, const Vec3& vInput)
  166. {
  167.         // no mesh is perfect
  168.         //              assert(IsNormalized(vFrom));
  169.         // no mesh is perfect
  170.         //              assert(IsNormalized(vTo));
  171.  
  172.         // rotation axis
  173.         Vec3 vRotAxis = vFrom.cross(vTo);
  174.  
  175.         float fSin = vRotAxis.len();
  176.         float fCos = vFrom.Dot(vTo);
  177.  
  178.         // no rotation
  179.         if (fSin < 0.00001f)
  180.                 return vInput;
  181.  
  182.         // normalize
  183.         vRotAxis = vRotAxis * (1.0f / fSin);
  184.  
  185.         // perpendicular to vRotAxis and vFrom90deg
  186.         Vec3 vFrom90deg = (vRotAxis.cross(vFrom)).normalize();
  187.  
  188.         // Base is vFrom,vFrom90deg,vRotAxis
  189.         float fXInPlane = vFrom.Dot(vInput);
  190.         float fYInPlane = vFrom90deg.Dot(vInput);
  191.  
  192.         Vec3 a = vFrom * (fXInPlane * fCos - fYInPlane * fSin);
  193.         Vec3 b = vFrom90deg * (fXInPlane * fSin + fYInPlane * fCos);
  194.         Vec3 c = vRotAxis * (vRotAxis.Dot(vInput));
  195.  
  196.         return a + b + c;
  197. }
  198.  
  199. eCalculateTangentSpaceErrorCode CTangentSpaceCalculation::CalculateTangentSpace(
  200.   const ITriangleInputProxy& inInput,
  201.   const bool bUseCustomNormals,
  202.   const bool bIgnoreDegeneracies,
  203.   string& errorMessage)
  204. {
  205.         if (bUseCustomNormals)
  206.         {
  207.                 return CalculateTangentSpaceMikk(inInput, errorMessage);
  208.         }
  209.  
  210.         uint32 dwTriCount = inInput.GetTriangleCount();
  211.  
  212.         // not a number in texture coordinates
  213.         bool bTextureCoordinatesBroken = false;
  214.  
  215.         // clear result
  216.         m_baseVectors.clear();
  217.         m_trianglesBaseAssigment.clear();
  218.         m_trianglesBaseAssigment.reserve(dwTriCount);
  219.         assert(m_baseVectors.empty());
  220.         assert(m_trianglesBaseAssigment.empty());
  221.  
  222.         // second=index into m_BaseVectors, generated output data
  223.         std::multimap<CBaseIndex, uint32, CBaseIndexOrder> mBaseMap;
  224.         // base vectors per triangle
  225.         std::vector<CBase33> vTriangleBase;
  226.  
  227.         // calculate the base vectors per triangle -------------------------------------------
  228.         {
  229.                 eCalculateTangentSpaceErrorCode errorCode = CALCULATE_TANGENT_SPACE_NO_ERRORS;
  230.                 for (uint32 i = 0; i < dwTriCount; i++)
  231.                 {
  232.                         // get data from caller ---------------------------
  233.                         uint32 dwPos[3], dwNorm[3], dwUV[3];
  234.  
  235.                         inInput.GetTriangleIndices(i, dwPos, dwNorm, dwUV);
  236.  
  237.                         Vec3 vPos[3];
  238.                         Vec2 vUV[3];
  239.  
  240.                         for (int e = 0; e < 3; e++)
  241.                         {
  242.                                 inInput.GetPos(dwPos[e], vPos[e]);
  243.                                 inInput.GetUV(dwUV[e], vUV[e]);
  244.                         }
  245.  
  246.                         // calculate tangent vectors ---------------------------
  247.  
  248.                         Vec3 vA = vPos[1] - vPos[0];
  249.                         Vec3 vB = vPos[2] - vPos[0];
  250.                         Vec3 vC = vPos[2] - vPos[1];
  251.  
  252.                         if (!bIgnoreDegeneracies)
  253.                         {
  254.                                 if (vA.IsZero())
  255.                                 {
  256.                                         //vert 0 and 1 have the same coordinates
  257.                                         errorMessage.Format("Vertices 0 and 1 have the same coordinate: (%f : %f : %f)\n", vPos[0].x, vPos[0].y, vPos[0].z);
  258.                                         errorCode = VERTICES_SHARING_COORDINATES;
  259.                                         continue;
  260.                                 }
  261.  
  262.                                 if (vB.IsZero())
  263.                                 {
  264.                                         //vert 2 and 0 have the same coordinates
  265.                                         errorMessage.Format("Vertices 2 and 0 have the same coordinate: (%f : %f : %f)\n", vPos[0].x, vPos[0].y, vPos[0].z);
  266.                                         errorCode = VERTICES_SHARING_COORDINATES;
  267.                                         continue;
  268.                                 }
  269.  
  270.                                 if (vC.IsZero())
  271.                                 {
  272.                                         //vert 2 and 1 have the same coordinates
  273.                                         errorMessage.Format("Vertices 2 and 1 have the same coordinate: (%f : %f : %f)\n", vPos[1].x, vPos[1].y, vPos[1].z);
  274.                                         errorCode = VERTICES_SHARING_COORDINATES;
  275.                                         continue;
  276.                                 }
  277.                         }
  278.  
  279.                         float fDeltaU1 = vUV[1].x - vUV[0].x;
  280.                         float fDeltaU2 = vUV[2].x - vUV[0].x;
  281.                         float fDeltaV1 = vUV[1].y - vUV[0].y;
  282.                         float fDeltaV2 = vUV[2].y - vUV[0].y;
  283.  
  284.                         float div = (fDeltaU1 * fDeltaV2 - fDeltaU2 * fDeltaV1);
  285.  
  286.                         if (_isnan(div))
  287.                         {
  288.                                 errorMessage.Format("Vertices 0,1,2 have broken texture coordinates v0:(%f : %f : %f) v1:(%f : %f : %f) v2:(%f : %f : %f)\n", vPos[0].x, vPos[0].y, vPos[0].z, vPos[1].x, vPos[1].y, vPos[1].z, vPos[2].x, vPos[2].y, vPos[2].z);
  289.                                 bTextureCoordinatesBroken = true;
  290.                                 div = 0.0f;
  291.                         }
  292.  
  293.                         Vec3 vU, vV, vN = (vA.cross(vB)).normalize();
  294.  
  295.                         if (div != 0.0)
  296.                         {
  297.                                 //      2D triangle area = (u1*v2-u2*v1)/2
  298.                                 float a = fDeltaV2;           // /div was removed - no required because of normalize()
  299.                                 float b = -fDeltaV1;
  300.                                 float c = -fDeltaU2;
  301.                                 float d = fDeltaU1;
  302.  
  303.                                 // /fAreaMul2*fAreaMul2 was optimized away -> small triangles in UV should contribute less and
  304.                                 // less artifacts (no divide and multiply)
  305.                                 vU = (vA * a + vB * b) * fsgnf(div);
  306.                                 vV = (vA * c + vB * d) * fsgnf(div);
  307.                         }
  308.                         else
  309.                         {
  310.                                 vU = Vec3(1, 0, 0);
  311.                                 vV = Vec3(0, 1, 0);
  312.                         }
  313.  
  314.                         vTriangleBase.push_back(CBase33(vU, vV, vN));
  315.                 }
  316.                 if (errorCode != CALCULATE_TANGENT_SPACE_NO_ERRORS)
  317.                 {
  318.                         return errorCode;
  319.                 }
  320.         }
  321.  
  322.         // distribute the normals to the vertices
  323.         {
  324.                 // we create a new tangent base for every vertex index that has a different normal (later we split further for mirrored use)
  325.                 // and sum the base vectors (weighted by angle and mirrored if necessary)
  326.                 for (uint32 i = 0; i < dwTriCount; i++)
  327.                 {
  328.                         uint32 e;
  329.  
  330.                         // get data from caller ---------------------------
  331.                         uint32 dwPos[3], dwNorm[3], dwUV[3];
  332.  
  333.                         inInput.GetTriangleIndices(i, dwPos, dwNorm, dwUV);
  334.                         CBase33 TriBase = vTriangleBase[i];
  335.                         Vec3 vPos[3];
  336.  
  337.                         for (e = 0; e < 3; e++)
  338.                         {
  339.                                 inInput.GetPos(dwPos[e], vPos[e]);
  340.                         }
  341.  
  342.                         // for each triangle vertex
  343.                         for (e = 0; e < 3; e++)
  344.                         {
  345.                                 // weight by angle to fix the L-Shape problem
  346.                                 float fWeight = CalcAngleBetween(vPos[(e + 2) % 3] - vPos[e], vPos[(e + 1) % 3] - vPos[e]);
  347.  
  348.                                 if (fWeight <= 0.0f)
  349.                                         fWeight = 0.0001f;
  350.  
  351.                                 AddNormal2Base(mBaseMap, dwPos[e], dwNorm[e], TriBase.n * fWeight);
  352.                         }
  353.                 }
  354.         }
  355.  
  356.         // distribute the uv vectors to the vertices
  357.         {
  358.                 // we create a new tangent base for every vertex index that has a different normal
  359.                 // if the base vectors does'nt fit we split as well
  360.                 for (uint32 i = 0; i < dwTriCount; i++)
  361.                 {
  362.                         uint32 e;
  363.  
  364.                         // get data from caller ---------------------------
  365.                         uint32 dwPos[3], dwNorm[3], dwUV[3];
  366.  
  367.                         CTriBaseIndex Indx;
  368.                         inInput.GetTriangleIndices(i, dwPos, dwNorm, dwUV);
  369.                         CBase33 TriBase = vTriangleBase[i];
  370.                         Vec3 vPos[3];
  371.  
  372.                         for (e = 0; e < 3; e++)
  373.                         {
  374.                                 inInput.GetPos(dwPos[e], vPos[e]);
  375.                         }
  376.  
  377.                         // for each triangle vertex
  378.                         for (e = 0; e < 3; e++)
  379.                         {
  380.                                 // weight by angle to fix the L-Shape problem
  381.                                 float fWeight = CalcAngleBetween(vPos[(e + 2) % 3] - vPos[e], vPos[(e + 1) % 3] - vPos[e]);
  382.  
  383.                                 Indx.p[e] = AddUV2Base(mBaseMap, dwPos[e], dwNorm[e], TriBase.u * fWeight, TriBase.v * fWeight, TriBase.n.normalize(), bIgnoreDegeneracies);
  384.                         }
  385.  
  386.                         m_trianglesBaseAssigment.push_back(Indx);
  387.                 }
  388.         }
  389.  
  390.         // adjust the base vectors per vertex -------------------------------------------
  391.         {
  392.                 std::vector<CBase33>::iterator it;
  393.  
  394.                 for (it = m_baseVectors.begin(); it != m_baseVectors.end(); ++it)
  395.                 {
  396.                         CBase33& ref = (*it);
  397.  
  398.                         // rotate u and v in n plane
  399.                         {
  400.                                 Vec3 vUout, vVout, vNout;
  401.  
  402.                                 vNout = ref.n;
  403.                                 vNout.normalize();
  404.  
  405.                                 // project u in n plane
  406.                                 // project v in n plane
  407.                                 vUout = ref.u - vNout * (vNout.Dot(ref.u));
  408.                                 vVout = ref.v - vNout * (vNout.Dot(ref.v));
  409.  
  410.                                 ref.u = vUout;
  411.                                 ref.u.normalize();
  412.  
  413.                                 ref.v = vVout;
  414.                                 ref.v.normalize();
  415.  
  416.                                 ref.n = vNout;
  417.  
  418.                                 //assert(ref.u.x>=-1 && ref.u.x<=1);
  419.                                 //assert(ref.u.y>=-1 && ref.u.y<=1);
  420.                                 //assert(ref.u.z>=-1 && ref.u.z<=1);
  421.                                 //assert(ref.v.x>=-1 && ref.v.x<=1);
  422.                                 //assert(ref.v.y>=-1 && ref.v.y<=1);
  423.                                 //assert(ref.v.z>=-1 && ref.v.z<=1);
  424.                                 //assert(ref.n.x>=-1 && ref.n.x<=1);
  425.                                 //assert(ref.n.y>=-1 && ref.n.y<=1);
  426.                                 //assert(ref.n.z>=-1 && ref.n.z<=1);
  427.                         }
  428.                 }
  429.         }
  430.  
  431.         return bTextureCoordinatesBroken ? BROKEN_TEXTURE_COORDINATES : CALCULATE_TANGENT_SPACE_NO_ERRORS;
  432. }
  433.  
  434. uint32 CTangentSpaceCalculation::AddUV2Base(std::multimap<CBaseIndex, uint32, CBaseIndexOrder>& inMap,
  435.                                             const uint32 indwPosNo, const uint32 indwNormNo, const Vec3& inU, const Vec3& inV, const Vec3& inNormN,
  436.                                             bool bIgnoreDegeneracies)
  437. {
  438.         CBaseIndex Indx;
  439.  
  440.         Indx.m_posIndex = indwPosNo;
  441.         Indx.m_normIndex = indwNormNo;
  442.  
  443.         std::multimap<CBaseIndex, uint32, CBaseIndexOrder>::iterator iFind, iFindEnd;
  444.  
  445.         iFind = inMap.lower_bound(Indx);
  446.  
  447.         assert(iFind != inMap.end());
  448.  
  449.         Vec3 vNormal = m_baseVectors[(*iFind).second].n;
  450.  
  451.         iFindEnd = inMap.upper_bound(Indx);
  452.  
  453.         uint32 dwBaseUVIndex = 0xffffffff;                          // init with not found
  454.  
  455.         bool bParity = inU.cross(inV).Dot(inNormN) > 0.0f;
  456.  
  457.         for (; iFind != iFindEnd; ++iFind)
  458.         {
  459.                 CBase33& refFound = m_baseVectors[(*iFind).second];
  460.  
  461.                 if (!refFound.u.IsZero())
  462.                 {
  463.                         bool bParityRef = refFound.u.cross(refFound.v).Dot(refFound.n) > 0.0f;
  464.                         bool bParityCheck = (bParityRef == bParity);
  465.  
  466.                         if (!bParityCheck) continue;
  467.  
  468.                         //              bool bHalfAngleCheck=normalize(inU+inV) * normalize(refFound.u+refFound.v) > 0.0f;
  469.                         Vec3 normRefFound = refFound.n;
  470.                         normRefFound.normalize();
  471.  
  472.                         Vec3 uvRefSum = refFound.u + refFound.v;
  473.                         uvRefSum.normalize();
  474.  
  475.                         Vec3 vRotHalf = Rotate(normRefFound, inNormN, uvRefSum);
  476.  
  477.                         Vec3 uvInSum = inU + inV;
  478.                         uvInSum.normalize();
  479.                         bool bHalfAngleCheck = uvInSum.Dot(vRotHalf) > 0.0f;
  480.                         //              bool bHalfAngleCheck=normalize(normalize(inU)+normalize(inV)) * normalize(normalize(refFound.u)+normalize(refFound.v)) > 0.0f;
  481.  
  482.                         if (!bHalfAngleCheck) continue;
  483.                 }
  484.  
  485.                 dwBaseUVIndex = (*iFind).second;
  486.                 break;
  487.         }
  488.  
  489.         // not found
  490.         if (dwBaseUVIndex == 0xffffffff)
  491.         {
  492.                 // otherwise create a new base
  493.                 CBase33 Base(Vec3(0, 0, 0), Vec3(0, 0, 0), vNormal);
  494.  
  495.                 dwBaseUVIndex = m_baseVectors.size();
  496.  
  497.                 inMap.insert(std::pair<CBaseIndex, uint32>(Indx, dwBaseUVIndex));
  498.                 m_baseVectors.push_back(Base);
  499.         }
  500.  
  501.         CBase33& refBaseUV = m_baseVectors[dwBaseUVIndex];
  502.  
  503.         refBaseUV.u = refBaseUV.u + inU;
  504.         refBaseUV.v = refBaseUV.v + inV;
  505.  
  506.         if (!bIgnoreDegeneracies)
  507.         {
  508.                 //no mesh is perfect
  509.                 if (inU.x != 0.0f || inU.y != 0.0f || inU.z != 0.0f)
  510.                         assert(refBaseUV.u.x != 0.0f || refBaseUV.u.y != 0.0f || refBaseUV.u.z != 0.0f);
  511.                 // no mesh is perfect
  512.                 if (inV.x != 0.0f || inV.y != 0.0f || inV.z != 0.0f)
  513.                         assert(refBaseUV.v.x != 0.0f || refBaseUV.v.y != 0.0f || refBaseUV.v.z != 0.0f);
  514.         }
  515.  
  516.         return dwBaseUVIndex;
  517. }
  518.  
  519. void CTangentSpaceCalculation::AddNormal2Base(std::multimap<CBaseIndex, uint32, CBaseIndexOrder>& inMap, const uint32 indwPosNo, const uint32 indwNormNo, const Vec3& inNormal)
  520. {
  521.         CBaseIndex Indx;
  522.  
  523.         Indx.m_posIndex = indwPosNo;
  524.         Indx.m_normIndex = indwNormNo;
  525.  
  526.         std::multimap<CBaseIndex, uint32, CBaseIndexOrder>::iterator iFind = inMap.find(Indx);
  527.  
  528.         uint32 dwBaseNIndex;
  529.  
  530.         if (iFind != inMap.end())
  531.         {
  532.                 dwBaseNIndex = (*iFind).second;
  533.         }
  534.         else
  535.         {
  536.                 CBase33 Base(Vec3(0, 0, 0), Vec3(0, 0, 0), Vec3(0, 0, 0));
  537.  
  538.                 dwBaseNIndex = m_baseVectors.size();
  539.                 inMap.insert(std::pair<CBaseIndex, uint32>(Indx, dwBaseNIndex));
  540.                 m_baseVectors.push_back(Base);
  541.         }
  542.  
  543.         CBase33& refBaseN = m_baseVectors[dwBaseNIndex];
  544.  
  545.         refBaseN.n = refBaseN.n + inNormal;
  546. }
  547.  
  548. void CTangentSpaceCalculation::GetBase(const uint32 indwPos, float* outU, float* outV, float* outN)
  549. {
  550.         CBase33& base = m_baseVectors[indwPos];
  551.  
  552.         outU[0] = base.u.x;
  553.         outV[0] = base.v.x;
  554.         outN[0] = base.n.x;
  555.         outU[1] = base.u.y;
  556.         outV[1] = base.v.y;
  557.         outN[1] = base.n.y;
  558.         outU[2] = base.u.z;
  559.         outV[2] = base.v.z;
  560.         outN[2] = base.n.z;
  561. }
  562.  
  563. void CTangentSpaceCalculation::GetTriangleBaseIndices(const uint32 indwTriNo, uint32 outdwBase[3])
  564. {
  565.         assert(indwTriNo < m_trianglesBaseAssigment.size());
  566.         CTriBaseIndex& indx = m_trianglesBaseAssigment[indwTriNo];
  567.  
  568.         for (uint32 i = 0; i < 3; i++)
  569.                 outdwBase[i] = indx.p[i];
  570. }
  571.  
  572. size_t CTangentSpaceCalculation::GetBaseCount()
  573. {
  574.         return m_baseVectors.size();
  575. }
  576.  
  577. static int MikkGetNumFaces(const SMikkTSpaceContext* pContext)
  578. {
  579.         SMikkMesh* mikkMesh = (SMikkMesh*)pContext->m_pUserData;
  580.         return mikkMesh->mikkNumFaces;
  581. }
  582.  
  583. static int MikkGetNumVerticesOfFace(const SMikkTSpaceContext* pContext, const int iFace)
  584. {
  585.         return 3;
  586. }
  587.  
  588. static void MikkGetPosition(const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert)
  589. {
  590.         SMikkMesh* mikkMesh = (SMikkMesh*)pContext->m_pUserData;
  591.         const SMikkFace& face = mikkMesh->mikkFaces[iFace];
  592.  
  593.         const Vec3& pos = mikkMesh->mikkVerts[face.vertexOffset + iVert].pos;
  594.         fvPosOut[0] = pos.x;
  595.         fvPosOut[1] = pos.y;
  596.         fvPosOut[2] = pos.z;
  597. }
  598.  
  599. static void MikkGetNormal(const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert)
  600. {
  601.         SMikkMesh* mikkMesh = (SMikkMesh*)pContext->m_pUserData;
  602.         const SMikkFace& face = mikkMesh->mikkFaces[iFace];
  603.  
  604.         const Vec3& normal = mikkMesh->mikkVerts[face.vertexOffset + iVert].norm;
  605.         fvNormOut[0] = normal.x;
  606.         fvNormOut[1] = normal.y;
  607.         fvNormOut[2] = normal.z;
  608. }
  609.  
  610. static void MikkGetTexCoord(const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert)
  611. {
  612.         SMikkMesh* mikkMesh = (SMikkMesh*)pContext->m_pUserData;
  613.         const SMikkFace& face = mikkMesh->mikkFaces[iFace];
  614.  
  615.         const Vec2& tan = mikkMesh->mikkVerts[face.vertexOffset + iVert].texc;
  616.         fvTexcOut[0] = tan.x;
  617.         fvTexcOut[1] = tan.y;
  618. }
  619.  
  620. static void MikkSetTSpace(const SMikkTSpaceContext* pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT, const tbool bIsOrientationPreserving, const int iFace, const int iVert)
  621. {
  622.         SMikkMesh* mikkMesh = (SMikkMesh*)pContext->m_pUserData;
  623.         const SMikkFace& face = mikkMesh->mikkFaces[iFace];
  624.         const int index = face.vertexOffset + iVert;
  625.  
  626.         mikkMesh->mikkVerts[index].tang = Vec3(fvTangent[0], fvTangent[1], fvTangent[2]);
  627.         mikkMesh->mikkVerts[index].bitang = Vec3(fvBiTangent[0], fvBiTangent[1], fvBiTangent[2]);
  628.         mikkMesh->mikkVerts[index].magST.x = fMagS;
  629.         mikkMesh->mikkVerts[index].magST.y = fMagT;
  630. }
  631.  
  632. eCalculateTangentSpaceErrorCode CTangentSpaceCalculation::CalculateTangentSpaceMikk(const ITriangleInputProxy& proxy, string& errorMessage)
  633. {
  634.         const uint32 numFaces = proxy.GetTriangleCount();
  635.  
  636.         // prepare the working mesh for mikkelsen algorithm
  637.         // when custom normals are specified, we'll use them
  638.         SMikkMesh mikkMesh;
  639.         mikkMesh.mikkNumFaces = numFaces;
  640.         mikkMesh.mikkVerts.resize(numFaces * 3);
  641.         mikkMesh.mikkFaces.resize(numFaces);
  642.  
  643.         for (uint32 f = 0; f < numFaces; ++f)
  644.         {
  645.                 uint32 outdwPos[3];
  646.                 uint32 outdwNorm[3];
  647.                 uint32 outdwUV[3];
  648.                 proxy.GetTriangleIndices(f, outdwPos, outdwNorm, outdwUV);
  649.  
  650.                 mikkMesh.mikkFaces[f].vertexOffset = f * 3;
  651.                 mikkMesh.mikkFaces[f].nrOriginalFace = f;
  652.  
  653.                 for (uint32 vId = 0; vId < 3; ++vId)
  654.                 {
  655.                         SMikkVertex& vert(mikkMesh.mikkVerts[mikkMesh.mikkFaces[f].vertexOffset + vId]);
  656.  
  657.                         proxy.GetPos(outdwPos[vId], vert.pos);
  658.                         proxy.GetNorm(f, vId, vert.norm);
  659.                         proxy.GetUV(outdwUV[vId], vert.texc);
  660.  
  661.                         vert.tang = Vec3(1.0f, 0.0f, 0.0f);
  662.                         vert.bitang = Vec3(0.0f, 1.0f, 0.0f);
  663.                 }
  664.         }
  665.  
  666.         // prepare mikkelsen interface
  667.         SMikkTSpaceInterface mikkInterface;
  668.         memset(&mikkInterface, 0, sizeof(SMikkTSpaceInterface));
  669.  
  670.         mikkInterface.m_getNumFaces = MikkGetNumFaces;
  671.         mikkInterface.m_getNumVerticesOfFace = MikkGetNumVerticesOfFace;
  672.         mikkInterface.m_getPosition = MikkGetPosition;
  673.         mikkInterface.m_getNormal = MikkGetNormal;
  674.         mikkInterface.m_getTexCoord = MikkGetTexCoord;
  675.         mikkInterface.m_setTSpace = MikkSetTSpace;
  676.  
  677.         SMikkTSpaceContext mikkContext;
  678.         memset(&mikkContext, 0, sizeof(SMikkTSpaceContext));
  679.         mikkContext.m_pUserData = &mikkMesh;
  680.         mikkContext.m_pInterface = &mikkInterface;
  681.  
  682.         // generate tangent basis
  683.         bool res = genTangSpaceDefault(&mikkContext) != 0;
  684.         if (!res)
  685.         {
  686.                 errorMessage = "Failed to allocate memory for Mikkelsen Tangent Basis algorithm.";
  687.                 return MEMORY_ALLOCATION_FAILED;
  688.         }
  689.  
  690.         m_baseVectors.clear();
  691.         m_trianglesBaseAssigment.clear();
  692.         m_trianglesBaseAssigment.resize(proxy.GetTriangleCount());
  693.  
  694.         std::map<CBase33, int, CBase33PredicateLess> uniqueBaseVectors;
  695.         std::map<CBase33, int, CBase33PredicateLess>::const_iterator it;
  696.  
  697.         // remove tangent basis duplicates and add them to the mesh
  698.         for (int f = 0; f < mikkMesh.mikkNumFaces; ++f)
  699.         {
  700.                 const SMikkFace& face = mikkMesh.mikkFaces[f];
  701.  
  702.                 CTriBaseIndex tbi;
  703.                 for (int ii = 0; ii < 3; ++ii)
  704.                 {
  705.                         const int index = face.vertexOffset + ii;
  706.                         const SMikkVertex& vert = mikkMesh.mikkVerts[index];
  707.  
  708.                         CBase33 base;
  709.                         base.u = vert.tang;
  710.                         base.v = vert.bitang;
  711.  
  712.                         float fNorm[3];
  713.                         MikkGetNormal(&mikkContext, &fNorm[0], face.nrOriginalFace, ii);
  714.  
  715.                         base.n.x = fNorm[0];
  716.                         base.n.y = fNorm[1];
  717.                         base.n.z = fNorm[2];
  718.  
  719.                         int val;
  720.                         it = uniqueBaseVectors.find(base);
  721.                         if (it != uniqueBaseVectors.end())
  722.                                 val = it->second;
  723.                         else
  724.                         {
  725.                                 val = m_baseVectors.size();
  726.                                 m_baseVectors.push_back(base);
  727.                                 uniqueBaseVectors[base] = val;
  728.                         }
  729.                         tbi.p[ii] = val;
  730.                 }
  731.                 m_trianglesBaseAssigment[face.nrOriginalFace] = tbi;
  732.         }
  733.  
  734.         return CALCULATE_TANGENT_SPACE_NO_ERRORS;
  735. }
  736.  
downloadTangentSpaceCalculation.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top