static STSpace AvgTSpace(ref STSpace pTS0, ref STSpace pTS1) { STSpace ts_res = new STSpace(); if (pTS0.fMagS == pTS1.fMagS && pTS0.fMagT == pTS1.fMagT && pTS0.vOs.Equals(pTS1.vOs) && pTS1.vOt.Equals(pTS1.vOt)) { ts_res.fMagS = pTS0.fMagS; ts_res.fMagT = pTS0.fMagT; ts_res.vOs = pTS0.vOs; ts_res.vOt = pTS0.vOt; } else { ts_res.fMagS = 0.5f * (pTS0.fMagS + pTS1.fMagS); ts_res.fMagT = 0.5f * (pTS0.fMagT + pTS1.fMagT); ts_res.vOs = pTS0.vOs + pTS0.vOs; ts_res.vOt = pTS0.vOt + pTS0.vOt; if (VNotZero(ref ts_res.vOs)) { ts_res.vOs.Normalize(); } if (VNotZero(ref ts_res.vOt)) { ts_res.vOt.Normalize(); } } return(ts_res); }
static bool GenerateTSpaces(ref STSpace[] psTspace, ref STriInfo[] pTriInfos, SGroup[] pGroups, int iNrActiveGroups, int[] piTriListIn, int[] pGroupTriangleBuffer, float fThresCos, ref SMikkTSpaceContext context) { STSpace[] pSubGroupTSpace = null; SSubGroup[] pUniSubGroups = null; int[] pTmpMembers = null; int iMaxNrFaces = 0, iUniqueTSpaces = 0, g = 0, i = 0; for (g = 0; g < iNrActiveGroups; ++g) { if (iMaxNrFaces < pGroups[g].iNrFaces) { iMaxNrFaces = pGroups[g].iNrFaces; } } if (iMaxNrFaces == 0) { return(true); } pSubGroupTSpace = new STSpace[iMaxNrFaces]; pUniSubGroups = new SSubGroup[iMaxNrFaces]; pTmpMembers = new int[iMaxNrFaces]; iUniqueTSpaces = 0; for (g = 0; g < iNrActiveGroups; ++g) { int iUniqueSubGroups = 0; for (i = 0; i < pGroups[g].iNrFaces; ++i) { int f = pGroupTriangleBuffer[pGroups[g].faceOffset]; int index = -1, iVertIndex = -1, iOF_1 = -1, iMembers = 0, j = 0, l = 0; SSubGroup tmp_group; bool bFound = false; Vector3 n = Vector3.Zero, vOs = Vector3.Zero, vOt = Vector3.Zero; if (pTriInfos[f].AssignedGroup[0] == pGroups[g]) { index = 0; } else if (pTriInfos[f].AssignedGroup[1] == pGroups[g]) { index = 1; } else if (pTriInfos[f].AssignedGroup[2] == pGroups[g]) { index = 2; } iVertIndex = piTriListIn[f * 3 + index]; n = GetNormal(ref context, iVertIndex); vOs = pTriInfos[f].vOs - (Vector3.Dot(n, pTriInfos[f].vOs) * n); vOt = pTriInfos[f].vOt - (Vector3.Dot(n, pTriInfos[f].vOt) * n); if (VNotZero(ref vOs)) { vOs.Normalize(); } if (VNotZero(ref vOt)) { vOt.Normalize(); } iOF_1 = pTriInfos[f].iOrgFaceNumber; iMembers = 0; for (j = 0; j < pGroups[g].iNrFaces; ++j) { int t = pGroupTriangleBuffer[pGroups[g].faceOffset + j]; int iOf_2 = pTriInfos[t].iOrgFaceNumber; Vector3 vOs2 = (pTriInfos[t].vOs - (Vector3.Dot(n, pTriInfos[t].vOs) * n)); Vector3 vOt2 = (pTriInfos[t].vOt - (Vector3.Dot(n, pTriInfos[t].vOt) * n)); if (VNotZero(ref vOs2)) { vOs2.Normalize(); } if (VNotZero(ref vOt2)) { vOt2.Normalize(); } { bool bAny = ((pTriInfos[f].iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY) != 0; bool bSameOrgFace = iOF_1 == iOf_2; float fCosS = Vector3.Dot(vOs, vOs2); float fCosT = Vector3.Dot(vOt, vOt2); if (bAny || bSameOrgFace || (fCosS > fThresCos && fCosT > fThresCos)) { pTmpMembers[iMembers++] = t; } } } tmp_group.iNrFaces = iMembers; tmp_group.triMembers = new List <int>(pTmpMembers); if (iMembers > 1) { tmp_group.triMembers.Sort(); } bFound = false; l = 0; while (l < iUniqueSubGroups && !bFound) { bFound = CompareSubGroups(ref tmp_group, ref pUniSubGroups[l]); if (!bFound) { ++l; } } if (!bFound) { pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers; pUniSubGroups[iUniqueSubGroups].triMembers = new List <int>(tmp_group.triMembers); pSubGroupTSpace[iUniqueSubGroups] = EvalTspace(tmp_group.triMembers, iMembers, piTriListIn, ref pTriInfos, ref context, pGroups[g].iVertex); iUniqueSubGroups++; } { int iOffs = pTriInfos[f].iTSpacesOffs; int iVert = pTriInfos[f].vert_num[index]; if (psTspace[iOffs + iVert].iCounter == 1) { psTspace[iOffs + iVert] = AvgTSpace(ref psTspace[iOffs + iVert], ref pSubGroupTSpace[l]); psTspace[iOffs + iVert].iCounter = 2; psTspace[iOffs + iVert].bOrient = pGroups[g].bOrientPreservering; } else { psTspace[iOffs + iVert] = pSubGroupTSpace[l]; psTspace[iOffs + iVert].iCounter = 1; psTspace[iOffs + iVert].bOrient = pGroups[g].bOrientPreservering; } } } iUniqueTSpaces += iUniqueSubGroups; } return(true); }
/// <summary> /// this version of Mikktspace only deals with triangles /// in order to save sometime in moving the code over to c# /// </summary> /// <param name="context"></param> /// <returns></returns> public static bool genTangSpace(ref SMikkTSpaceContext context, float fAngularThreshold) { int[] piTriListIn = null; int[] piGroupTrianglesBuffer = null; STriInfo[] pTriInfos = null; SGroup[] pGroups = null; STSpace[] psTspace = null; int iNrTrianglesIn = 0, f = 0, t = 0, i = 0; int iNrTSPaces = 0, iNrMaxGroups = 0; int iNrActiveGroups = 0, index = 0; int iNrFaces = context.m_pInterface.m_getNumFaces(ref context); float fThresCos = (float)Math.Cos((fAngularThreshold * ((float)Math.PI / 180.0f))); for (f = 0; f < iNrFaces; f++) { int verts = context.m_pInterface.m_getNumVerticesOfFace(ref context, f); if (verts == 3) { iNrTrianglesIn++; } } if (iNrTrianglesIn <= 0) { return(false); } piTriListIn = new int[3 * iNrTrianglesIn]; pTriInfos = new STriInfo[iNrTrianglesIn]; iNrTSPaces = GenerateInitialVerticesIndexList(ref pTriInfos, piTriListIn, ref context, iNrTrianglesIn); GenerateSharedVerticesIndexList(piTriListIn, ref context, iNrTrianglesIn); InitTriInfo(ref pTriInfos, piTriListIn, ref context, iNrTrianglesIn); iNrMaxGroups = iNrTrianglesIn * 3; pGroups = new SGroup[iNrMaxGroups]; for (f = 0; f < iNrMaxGroups; f++) { pGroups[f] = new SGroup(); } piGroupTrianglesBuffer = new int[iNrTrianglesIn * 3]; try { iNrActiveGroups = Build4RuleGroups(ref pTriInfos, ref pGroups, piGroupTrianglesBuffer, piTriListIn, iNrTrianglesIn); psTspace = new STSpace[iNrTSPaces]; for (t = 0; t < iNrTSPaces; t++) { psTspace[t].vOs.X = 1.0f; psTspace[t].fMagS = 1.0f; psTspace[t].vOt.Y = 1.0f; psTspace[t].fMagT = 1.0f; } GenerateTSpaces(ref psTspace, ref pTriInfos, pGroups, iNrActiveGroups, piTriListIn, piGroupTrianglesBuffer, fThresCos, ref context); index = 0; for (f = 0; f < iNrFaces; f++) { int verts = context.m_pInterface.m_getNumVerticesOfFace(ref context, f); if (verts != 3) { continue; } for (i = 0; i < verts; ++i) { var pSpace = psTspace[index]; float[] tang = new float[] { pSpace.vOs.X, pSpace.vOs.Y, pSpace.vOs.Z }; float[] bitang = new float[] { pSpace.vOt.X, pSpace.vOt.Y, pSpace.vOt.Z }; context.m_pInterface.m_setTSpace(ref context, tang, bitang, pSpace.fMagS, pSpace.fMagT, pSpace.bOrient, f, i); context.m_pInterface.m_setTSpaceBasic(ref context, tang, pSpace.bOrient ? 1 : -1, f, i); ++index; } } } catch (Exception e) { Console.WriteLine(e.StackTrace); } return(true); }
static STSpace EvalTspace(List <int> face_indices, int iFaces, int[] piTriListIn, ref STriInfo[] pTriInfos, ref SMikkTSpaceContext context, int iVertexRepresentitive) { STSpace res = new STSpace(); float fAngleSum = 0; int face = 0; res.vOs = Vector3.Zero; res.vOt = Vector3.Zero; res.fMagS = 0; res.fMagT = 0; for (face = 0; face < iFaces; face++) { int f = face_indices[face]; if ((pTriInfos[f].iFlag & GROUP_WITH_ANY) == 0) { Vector3 n, vOs, vOt, p0, p1, p2, v1, v2; float fCos, fAngle, fMagS, fMagT; int i = -1, index = -1, i0 = -1, i1 = -1, i2 = -1; if (piTriListIn[3 * f] == iVertexRepresentitive) { i = 0; } else if (piTriListIn[3 * f + 1] == iVertexRepresentitive) { i = 1; } else if (piTriListIn[3 * f + 2] == iVertexRepresentitive) { i = 2; } index = piTriListIn[3 * f + i]; n = GetNormal(ref context, index); vOs = pTriInfos[f].vOs - (Vector3.Dot(n, pTriInfos[f].vOs) * n); vOt = pTriInfos[f].vOt - (Vector3.Dot(n, pTriInfos[f].vOt) * n); if (VNotZero(ref vOs)) { vOs.Normalize(); } if (VNotZero(ref vOt)) { vOt.Normalize(); } i2 = piTriListIn[3 * f + (i < 2 ? (i + 1) : 0)]; i1 = piTriListIn[3 * f + i]; i0 = piTriListIn[3 * f + (i > 0 ? (i - 1) : 2)]; p0 = GetPosition(ref context, i0); p1 = GetPosition(ref context, i1); p2 = GetPosition(ref context, i2); v1 = p0 - p1; v2 = p2 - p1; v1 = v1 - Vector3.Dot(n, v1) * n; v2 = v2 - Vector3.Dot(n, v2) * n; if (VNotZero(ref v1)) { v1.Normalize(); } if (VNotZero(ref v2)) { v2.Normalize(); } fCos = Vector3.Dot(v1, v2); fCos = fCos > 1 ? 1 : (fCos < -1 ? -1 : fCos); fAngle = (float)Math.Acos(fCos); fMagS = pTriInfos[f].fMagS; fMagT = pTriInfos[f].fMagT; res.vOs = res.vOs + vOs * fAngle; res.vOt = res.vOt + vOt * fAngle; res.fMagS += (fAngle * fMagS); res.fMagT += (fAngle * fMagT); fAngleSum += fAngle; } } if (VNotZero(ref res.vOs)) { res.vOs.Normalize(); } if (VNotZero(ref res.vOt)) { res.vOt.Normalize(); } if (fAngleSum > 0) { res.fMagS /= fAngleSum; res.fMagT /= fAngleSum; } return(res); }