2
0
Бранимир Караџић 5 жил өмнө
parent
commit
b8463e4974

+ 1 - 1
3rdparty/meshoptimizer/src/meshoptimizer.h

@@ -642,7 +642,7 @@ public:
 	}
 
 private:
-	void* blocks[16];
+	void* blocks[24];
 	size_t count;
 };
 

+ 55 - 56
3rdparty/meshoptimizer/src/simplifier.cpp

@@ -217,44 +217,35 @@ static bool hasEdge(const EdgeAdjacency& adjacency, unsigned int a, unsigned int
 	return false;
 }
 
-static unsigned int findWedgeEdge(const EdgeAdjacency& adjacency, const unsigned int* wedge, unsigned int a, unsigned int b)
+static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned int* loopback, size_t vertex_count, const EdgeAdjacency& adjacency, const unsigned int* remap, const unsigned int* wedge)
 {
-	unsigned int v = a;
+	memset(loop, -1, vertex_count * sizeof(unsigned int));
+	memset(loopback, -1, vertex_count * sizeof(unsigned int));
 
-	do
-	{
-		if (hasEdge(adjacency, v, b))
-			return v;
-
-		v = wedge[v];
-	} while (v != a);
-
-	return ~0u;
-}
+	// incoming & outgoing open edges: ~0u if no open edges, i if there are more than 1
+	// note that this is the same data as required in loop[] arrays; loop[] data is only valid for border/seam
+	// but here it's okay to fill the data out for other types of vertices as well
+	unsigned int* openinc = loopback;
+	unsigned int* openout = loop;
 
-static size_t countOpenEdges(const EdgeAdjacency& adjacency, unsigned int vertex, unsigned int* last = 0)
-{
-	size_t result = 0;
+	for (size_t i = 0; i < vertex_count; ++i)
+	{
+		unsigned int vertex = unsigned(i);
 
-	unsigned int count = adjacency.counts[vertex];
-	const unsigned int* data = adjacency.data + adjacency.offsets[vertex];
+		unsigned int count = adjacency.counts[vertex];
+		const unsigned int* data = adjacency.data + adjacency.offsets[vertex];
 
-	for (size_t i = 0; i < count; ++i)
-		if (!hasEdge(adjacency, data[i], vertex))
+		for (size_t j = 0; j < count; ++j)
 		{
-			result++;
+			unsigned int target = data[j];
 
-			if (last)
-				*last = data[i];
+			if (!hasEdge(adjacency, target, vertex))
+			{
+				openinc[target] = (openinc[target] == ~0u) ? vertex : target;
+				openout[vertex] = (openout[vertex] == ~0u) ? target : vertex;
+			}
 		}
-
-	return result;
-}
-
-static void classifyVertices(unsigned char* result, unsigned int* loop, size_t vertex_count, const EdgeAdjacency& adjacency, const unsigned int* remap, const unsigned int* wedge)
-{
-	for (size_t i = 0; i < vertex_count; ++i)
-		loop[i] = ~0u;
+	}
 
 #if TRACE
 	size_t lockedstats[4] = {};
@@ -270,22 +261,18 @@ static void classifyVertices(unsigned char* result, unsigned int* loop, size_t v
 			if (wedge[i] == i)
 			{
 				// no attribute seam, need to check if it's manifold
-				unsigned int v = 0;
-				size_t edges = countOpenEdges(adjacency, unsigned(i), &v);
+				unsigned int openi = openinc[i], openo = openout[i];
 
 				// note: we classify any vertices with no open edges as manifold
 				// this is technically incorrect - if 4 triangles share an edge, we'll classify vertices as manifold
 				// it's unclear if this is a problem in practice
-				// also note that we classify vertices as border if they have *one* open edge, not two
-				// this is because we only have half-edges - so a border vertex would have one incoming and one outgoing edge
-				if (edges == 0)
+				if (openi == ~0u && openo == ~0u)
 				{
 					result[i] = Kind_Manifold;
 				}
-				else if (edges == 1)
+				else if (openi != i && openo != i)
 				{
 					result[i] = Kind_Border;
-					loop[i] = v;
 				}
 				else
 				{
@@ -296,23 +283,18 @@ static void classifyVertices(unsigned char* result, unsigned int* loop, size_t v
 			else if (wedge[wedge[i]] == i)
 			{
 				// attribute seam; need to distinguish between Seam and Locked
-				unsigned int a = 0;
-				size_t a_count = countOpenEdges(adjacency, unsigned(i), &a);
-				unsigned int b = 0;
-				size_t b_count = countOpenEdges(adjacency, wedge[i], &b);
+				unsigned int w = wedge[i];
+				unsigned int openiv = openinc[i], openov = openout[i];
+				unsigned int openiw = openinc[w], openow = openout[w];
 
 				// seam should have one open half-edge for each vertex, and the edges need to "connect" - point to the same vertex post-remap
-				if (a_count == 1 && b_count == 1)
+				if (openiv != ~0u && openiv != i && openov != ~0u && openov != i &&
+				    openiw != ~0u && openiw != w && openow != ~0u && openow != w)
 				{
-					unsigned int ao = findWedgeEdge(adjacency, wedge, a, wedge[i]);
-					unsigned int bo = findWedgeEdge(adjacency, wedge, b, unsigned(i));
-
-					if (ao != ~0u && bo != ~0u)
+					if (remap[openiv] == remap[openow] && remap[openov] == remap[openiw] &&
+					    remap[openiw] == remap[openov] && remap[openow] == remap[openiv])
 					{
 						result[i] = Kind_Seam;
-
-						loop[i] = a;
-						loop[wedge[i]] = b;
 					}
 					else
 					{
@@ -557,7 +539,7 @@ static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
 	}
 }
 
-static void fillEdgeQuadrics(Quadric* vertex_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap, const unsigned char* vertex_kind, const unsigned int* loop)
+static void fillEdgeQuadrics(Quadric* vertex_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap, const unsigned char* vertex_kind, const unsigned int* loop, const unsigned int* loopback)
 {
 	for (size_t i = 0; i < index_count; i += 3)
 	{
@@ -571,9 +553,20 @@ static void fillEdgeQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
 			unsigned char k0 = vertex_kind[i0];
 			unsigned char k1 = vertex_kind[i1];
 
-			// check that i0 and i1 are border/seam and are on the same edge loop
-			// loop[] tracks half edges so we only need to check i0->i1
-			if (k0 != k1 || (k0 != Kind_Border && k0 != Kind_Seam) || loop[i0] != i1)
+			// check that either i0 or i1 are border/seam and are on the same edge loop
+			// note that we need to add the error even for edged that connect e.g. border & locked
+			// if we don't do that, the adjacent border->border edge won't have correct errors for corners
+			if (k0 != Kind_Border && k0 != Kind_Seam && k1 != Kind_Border && k1 != Kind_Seam)
+				continue;
+
+			if ((k0 == Kind_Border || k0 == Kind_Seam) && loop[i0] != i1)
+				continue;
+
+			if ((k1 == Kind_Border || k1 == Kind_Seam) && loopback[i1] != i0)
+				continue;
+
+			// seam edges should occur twice (i0->i1 and i1->i0) - skip redundant edges
+			if (kHasOpposite[k0][k1] && remap[i1] > remap[i0])
 				continue;
 
 			unsigned int i2 = indices[i + next[next[e]]];
@@ -583,7 +576,7 @@ static void fillEdgeQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
 			const float kEdgeWeightSeam = 1.f;
 			const float kEdgeWeightBorder = 10.f;
 
-			float edgeWeight = (k0 == Kind_Seam) ? kEdgeWeightSeam : kEdgeWeightBorder;
+			float edgeWeight = (k0 == Kind_Border || k1 == Kind_Border) ? kEdgeWeightBorder : kEdgeWeightSeam;
 
 			Quadric Q;
 			quadricFromTriangleEdge(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], edgeWeight);
@@ -1148,6 +1141,7 @@ static float interpolate(float y, float x0, float y0, float x1, float y1, float
 #ifndef NDEBUG
 unsigned char* meshopt_simplifyDebugKind = 0;
 unsigned int* meshopt_simplifyDebugLoop = 0;
+unsigned int* meshopt_simplifyDebugLoopBack = 0;
 #endif
 
 size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error)
@@ -1175,7 +1169,8 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
 	// classify vertices; vertex kind determines collapse rules, see kCanCollapse
 	unsigned char* vertex_kind = allocator.allocate<unsigned char>(vertex_count);
 	unsigned int* loop = allocator.allocate<unsigned int>(vertex_count);
-	classifyVertices(vertex_kind, loop, vertex_count, adjacency, remap, wedge);
+	unsigned int* loopback = allocator.allocate<unsigned int>(vertex_count);
+	classifyVertices(vertex_kind, loop, loopback, vertex_count, adjacency, remap, wedge);
 
 #if TRACE
 	size_t unique_positions = 0;
@@ -1199,7 +1194,7 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
 	memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric));
 
 	fillFaceQuadrics(vertex_quadrics, indices, index_count, vertex_positions, remap);
-	fillEdgeQuadrics(vertex_quadrics, indices, index_count, vertex_positions, remap, vertex_kind, loop);
+	fillEdgeQuadrics(vertex_quadrics, indices, index_count, vertex_positions, remap, vertex_kind, loop, loopback);
 
 	if (result != indices)
 		memcpy(result, indices, index_count * sizeof(unsigned int));
@@ -1258,6 +1253,7 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
 			break;
 
 		remapEdgeLoops(loop, vertex_count, collapse_remap);
+		remapEdgeLoops(loopback, vertex_count, collapse_remap);
 
 		size_t new_count = remapIndexBuffer(result, result_count, collapse_remap);
 		assert(new_count < result_count);
@@ -1295,6 +1291,9 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
 
 	if (meshopt_simplifyDebugLoop)
 		memcpy(meshopt_simplifyDebugLoop, loop, vertex_count * sizeof(unsigned int));
+
+	if (meshopt_simplifyDebugLoopBack)
+		memcpy(meshopt_simplifyDebugLoopBack, loopback, vertex_count * sizeof(unsigned int));
 #endif
 
 	return result_count;