Repository: zeux/meshoptimizer (language: cpp)

Issue:
obj -> glb with param -si XX，found many holes
glb result:
![image](https://user-images.githubusercontent.com/20105627/206109729-b48968e5-c4a7-4245-bf8f-414bb8d6033e.png)

obj:
![image](https://user-images.githubusercontent.com/20105627/206109792-afa0f876-59c9-4228-b8e9-a5b7f45cf18e.png)

obj files:
[test.zip](https://github.com/zeux/meshoptimizer/files/10173537/test.zip)


command:
gltfpack.exe -i test/Mesh-XR-YR-XL-YL_floor_0.obj -o test.glb -tc -noq -si 0.33


Discussion / hints:
This can be resolved by passing meshopt_SimplifyLockBorder to meshopt_simplify; however, doing this unconditionally is probably not a great idea, so this probably needs a separate command line option for gltfpack. I'd need to see if setting that to true or false by default makes more sense in context of gltfpack.

Fix patch:
diff --git a/gltf/gltfpack.cpp b/gltf/gltfpack.cpp
index 24d4226c5..412573f0f 100644
--- a/gltf/gltfpack.cpp
+++ b/gltf/gltfpack.cpp
@@ -1258,6 +1258,10 @@ int main(int argc, char** argv)
 		{
 			settings.simplify_aggressive = true;
 		}
+		else if (strcmp(arg, "-slb") == 0)
+		{
+			settings.simplify_lock_borders = true;
+		}
 #ifndef NDEBUG
 		else if (strcmp(arg, "-sd") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
 		{
@@ -1438,6 +1442,7 @@ int main(int argc, char** argv)
 			fprintf(stderr, "\nSimplification:\n");
 			fprintf(stderr, "\t-si R: simplify meshes targeting triangle count ratio R (default: 1; R should be between 0 and 1)\n");
 			fprintf(stderr, "\t-sa: aggressively simplify to the target ratio disregarding quality\n");
+			fprintf(stderr, "\t-slb: lock border vertices during simplification to avoid gaps on connected meshes\n");
 			fprintf(stderr, "\nVertices:\n");
 			fprintf(stderr, "\t-vp N: use N-bit quantization for positions (default: 14; N should be between 1 and 16)\n");
 			fprintf(stderr, "\t-vt N: use N-bit quantization for texture coordinates (default: 12; N should be between 1 and 16)\n");
diff --git a/gltf/gltfpack.h b/gltf/gltfpack.h
index 0193bee75..368f728fc 100644
--- a/gltf/gltfpack.h
+++ b/gltf/gltfpack.h
@@ -127,6 +127,7 @@ struct Settings
 
 	float simplify_threshold;
 	bool simplify_aggressive;
+	bool simplify_lock_borders;
 	float simplify_debug;
 
 	int meshlet_debug;
diff --git a/gltf/mesh.cpp b/gltf/mesh.cpp
index 45b3adf76..3bfe20ef2 100644
--- a/gltf/mesh.cpp
+++ b/gltf/mesh.cpp
@@ -529,7 +529,7 @@ static Stream* getStream(Mesh& mesh, cgltf_attribute_type type, int index = 0)
 	return 0;
 }
 
-static void simplifyMesh(Mesh& mesh, float threshold, bool aggressive)
+static void simplifyMesh(Mesh& mesh, float threshold, bool aggressive, bool lock_borders)
 {
 	assert(mesh.type == cgltf_primitive_type_triangles);
 
@@ -545,12 +545,13 @@ static void simplifyMesh(Mesh& mesh, float threshold, bool aggressive)
 	size_t target_index_count = size_t(double(mesh.indices.size() / 3) * threshold) * 3;
 	float target_error = 1e-2f;
 	float target_error_aggressive = 1e-1f;
+	unsigned int options = lock_borders ? meshopt_SimplifyLockBorder : 0;
 
 	if (target_index_count < 1)
 		return;
 
 	std::vector<unsigned int> indices(mesh.indices.size());
-	indices.resize(meshopt_simplify(&indices[0], &mesh.indices[0], mesh.indices.size(), positions->data[0].f, vertex_count, sizeof(Attr), target_index_count, target_error));
+	indices.resize(meshopt_simplify(&indices[0], &mesh.indices[0], mesh.indices.size(), positions->data[0].f, vertex_count, sizeof(Attr), target_index_count, target_error, options));
 	mesh.indices.swap(indices);
 
 	// Note: if the simplifier got stuck, we can try to reindex without normals/tangents and retry
@@ -764,7 +765,7 @@ void processMesh(Mesh& mesh, const Settings& settings)
 		reindexMesh(mesh);
 		filterTriangles(mesh);
 		if (settings.simplify_threshold < 1)
-			simplifyMesh(mesh, settings.simplify_threshold, settings.simplify_aggressive);
+			simplifyMesh(mesh, settings.simplify_threshold, settings.simplify_aggressive, settings.simplify_lock_borders);
 		optimizeMesh(mesh, settings.compressmore);
 		break;
 
@@ -801,7 +802,7 @@ void debugSimplify(const Mesh& source, Mesh& kinds, Mesh& loops, float ratio)
 	meshopt_simplifyDebugLoop = &loop[0];
 	meshopt_simplifyDebugLoopBack = &loopback[0];
 
-	simplifyMesh(mesh, ratio, /* aggressive= */ false);
+	simplifyMesh(mesh, ratio, /* aggressive= */ false, /* lock_borders= */ false);
 
 	meshopt_simplifyDebugKind = 0;
 	meshopt_simplifyDebugLoop = 0;


Test patch: