[Bf-blender-cvs] [9a5320aea38] blender-v2.79a-release: Fix T52818: Tangent space calculation is really slow for high-density mesh with degenerated topology

Sergey Sharybin noreply at git.blender.org
Mon Jan 8 16:55:44 CET 2018


Commit: 9a5320aea382810764b8206212fd77841e66c378
Author: Sergey Sharybin
Date:   Tue Sep 19 17:46:34 2017 +0500
Branches: blender-v2.79a-release
https://developer.blender.org/rB9a5320aea382810764b8206212fd77841e66c378

Fix T52818: Tangent space calculation is really slow for high-density mesh with degenerated topology

Now we replace O(N^2) computational complexity with O(N) extra memory penalty.
Memory is much cheaper than CPU time. Keep in mind, memory penalty is like
4 megabytes per 1M vertices.

===================================================================

M	intern/mikktspace/mikktspace.c

===================================================================

diff --git a/intern/mikktspace/mikktspace.c b/intern/mikktspace/mikktspace.c
index bbac8365d86..99e945d40ba 100644
--- a/intern/mikktspace/mikktspace.c
+++ b/intern/mikktspace/mikktspace.c
@@ -1817,11 +1817,101 @@ static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int i
 	assert(iNrTrianglesIn == t);
 }
 
-static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris)
+typedef struct VertReverseLookupContext {
+	tbool bIsInitialized;
+	int * pLookup;
+	int iMaxVertIndex;
+} VertReverseLookupContext;
+
+static void GenerateReverseLookup(
+        const int piTriListIn[],
+        const int iNrTrianglesIn,
+        VertReverseLookupContext *pLookupCtx)
+{
+	int t;
+	// Figure out what size of lookup array we need.
+	pLookupCtx->iMaxVertIndex = -1;
+	for (t=0; t<3*iNrTrianglesIn; t++)
+	{
+		int iVertIndex = piTriListIn[t];
+		if (iVertIndex > pLookupCtx->iMaxVertIndex) {
+			pLookupCtx->iMaxVertIndex = iVertIndex;
+		}
+	}
+	// Allocate memory.
+	if (pLookupCtx->iMaxVertIndex < 1)
+	{
+		// Nothing to allocate, all triangles are degenerate.
+		return;
+	}
+	pLookupCtx->pLookup = malloc(sizeof(int) * (pLookupCtx->iMaxVertIndex + 1));
+	if (pLookupCtx->pLookup == NULL)
+	{
+		// Most likely run out of memory.
+		return;
+	}
+	// Fill in lookup.
+	for (t=0; t<=pLookupCtx->iMaxVertIndex; t++) {
+		pLookupCtx->pLookup[t] = -1;
+	}
+	for (t=0; t<3*iNrTrianglesIn; t++)
+	{
+		int iVertIndex = piTriListIn[t];
+		if (pLookupCtx->pLookup[iVertIndex] != -1)
+		{
+			continue;
+		}
+		pLookupCtx->pLookup[iVertIndex] = t;
+	}
+}
+
+static int LookupVertexIndexFromGoodTriangle(
+        VertReverseLookupContext *pLookupCtx,
+        int piTriListIn[],
+        const int iNrTrianglesIn,
+        const int iVertexIndex)
+{
+	// Allocate lookup on demand.
+	if (!pLookupCtx->bIsInitialized)
+	{
+		GenerateReverseLookup(piTriListIn,
+		                      iNrTrianglesIn,
+		                      pLookupCtx);
+		pLookupCtx->bIsInitialized = TTRUE;
+	}
+	// Make sure vertex index is in the mapping.
+	if (iVertexIndex > pLookupCtx->iMaxVertIndex)
+	{
+		return -1;
+	}
+	if (pLookupCtx->pLookup == NULL) {
+		return -1;
+	}
+	// Perform actual lookup.
+	return pLookupCtx->pLookup[iVertexIndex];
+}
+
+static void FreeReverseLookup(VertReverseLookupContext *pLookupCtx)
+{
+	if (!pLookupCtx->bIsInitialized) {
+		return;
+	}
+	if (pLookupCtx->pLookup != NULL) {
+		free(pLookupCtx->pLookup);
+	}
+}
+
+static void DegenEpilogue(STSpace psTspace[],
+                          STriInfo pTriInfos[],
+                          int piTriListIn[],
+                          const SMikkTSpaceContext * pContext,
+                          const int iNrTrianglesIn,
+                          const int iTotTris)
 {
 	int t=0, i=0;
+	VertReverseLookupContext lookupCtx = { TFALSE };
 	// deal with degenerate triangles
-	// punishment for degenerate triangles is O(N^2)
+	// punishment for degenerate triangles is O(iNrTrianglesIn) extra memory.
 	for (t=iNrTrianglesIn; t<iTotTris; t++)
 	{
 		// degenerate triangles on a quad with one good triangle are skipped
@@ -1834,29 +1924,27 @@ static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriLis
 		for (i=0; i<3; i++)
 		{
 			const int index1 = piTriListIn[t*3+i];
-			// search through the good triangles
-			tbool bNotFound = TTRUE;
-			int j=0;
-			while (bNotFound && j<(3*iNrTrianglesIn))
+			int j = LookupVertexIndexFromGoodTriangle(&lookupCtx,
+			                                          piTriListIn,
+			                                          iNrTrianglesIn,
+			                                          index1);
+			if (j < 0)
 			{
-				const int index2 = piTriListIn[j];
-				if (index1==index2) bNotFound=TFALSE;
-				else ++j;
+				// Matching vertex from good triangle is not found.
+				continue;
 			}
 
-			if (!bNotFound)
-			{
-				const int iTri = j/3;
-				const int iVert = j%3;
-				const int iSrcVert=pTriInfos[iTri].vert_num[iVert];
-				const int iSrcOffs=pTriInfos[iTri].iTSpacesOffs;
-				const int iDstVert=pTriInfos[t].vert_num[i];
-				const int iDstOffs=pTriInfos[t].iTSpacesOffs;
-				// copy tspace
-				psTspace[iDstOffs+iDstVert] = psTspace[iSrcOffs+iSrcVert];
-			}
+			const int iTri = j/3;
+			const int iVert = j%3;
+			const int iSrcVert=pTriInfos[iTri].vert_num[iVert];
+			const int iSrcOffs=pTriInfos[iTri].iTSpacesOffs;
+			const int iDstVert=pTriInfos[t].vert_num[i];
+			const int iDstOffs=pTriInfos[t].iTSpacesOffs;
+			// copy tspace
+			psTspace[iDstOffs+iDstVert] = psTspace[iSrcOffs+iSrcVert];
 		}
 	}
+	FreeReverseLookup(&lookupCtx);
 
 	// deal with degenerate quads with one good triangle
 	for (t=0; t<iNrTrianglesIn; t++)



More information about the Bf-blender-cvs mailing list