summaryrefslogtreecommitdiffstats
path: root/thirdparty/meshoptimizer/patches
diff options
context:
space:
mode:
authorArseny Kapoulkine <arseny.kapoulkine@gmail.com>2023-11-02 14:12:35 -0700
committerArseny Kapoulkine <arseny.kapoulkine@gmail.com>2023-11-02 14:12:35 -0700
commitbe2b0fcddc981e5e5491cc626ef793a167772a48 (patch)
tree06f7dd4f8201fc29a48af0e499cbbad356d07cd0 /thirdparty/meshoptimizer/patches
parentc5f73a1783fbf35e2601134678c52ec813837384 (diff)
downloadredot-engine-be2b0fcddc981e5e5491cc626ef793a167772a48.tar.gz
Update thirdparty/meshoptimizer with distance-only error metric
This change replicates the distance-only metric patch which is now much smaller and cleaner, as upstream simplifier already tracks distance and attribute quadrics separately - it just doesn't store both errors in the collapse structures. The old two patches were removed as they are no longer needed.
Diffstat (limited to 'thirdparty/meshoptimizer/patches')
-rw-r--r--thirdparty/meshoptimizer/patches/attribute-aware-simplify-distance-only-metric.patch176
-rw-r--r--thirdparty/meshoptimizer/patches/attribute-aware-simplify.patch263
-rw-r--r--thirdparty/meshoptimizer/patches/distance-only-metric.patch39
3 files changed, 39 insertions, 439 deletions
diff --git a/thirdparty/meshoptimizer/patches/attribute-aware-simplify-distance-only-metric.patch b/thirdparty/meshoptimizer/patches/attribute-aware-simplify-distance-only-metric.patch
deleted file mode 100644
index 5cac985dc5..0000000000
--- a/thirdparty/meshoptimizer/patches/attribute-aware-simplify-distance-only-metric.patch
+++ /dev/null
@@ -1,176 +0,0 @@
-diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
-index d8d4a67391..3847afc736 100644
---- a/thirdparty/meshoptimizer/simplifier.cpp
-+++ b/thirdparty/meshoptimizer/simplifier.cpp
-@@ -20,7 +20,7 @@
- #define TRACESTATS(i) (void)0
- #endif
-
--#define ATTRIBUTES 8
-+#define ATTRIBUTES 3
-
- // This work is based on:
- // Michael Garland and Paul S. Heckbert. Surface simplification using quadric error metrics. 1997
-@@ -458,6 +458,7 @@ struct Collapse
- float error;
- unsigned int errorui;
- };
-+ float distance_error;
- };
-
- static float normalize(Vector3& v)
-@@ -538,6 +539,34 @@ static float quadricError(const Quadric& Q, const Vector3& v)
- return fabsf(r) * s;
- }
-
-+static float quadricErrorNoAttributes(const Quadric& Q, const Vector3& v)
-+{
-+ float rx = Q.b0;
-+ float ry = Q.b1;
-+ float rz = Q.b2;
-+
-+ rx += Q.a10 * v.y;
-+ ry += Q.a21 * v.z;
-+ rz += Q.a20 * v.x;
-+
-+ rx *= 2;
-+ ry *= 2;
-+ rz *= 2;
-+
-+ rx += Q.a00 * v.x;
-+ ry += Q.a11 * v.y;
-+ rz += Q.a22 * v.z;
-+
-+ float r = Q.c;
-+ r += rx * v.x;
-+ r += ry * v.y;
-+ r += rz * v.z;
-+
-+ float s = Q.w == 0.f ? 0.f : 1.f / Q.w;
-+
-+ return fabsf(r) * s;
-+}
-+
- static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d, float w)
- {
- float aw = a * w;
-@@ -693,7 +722,7 @@ static void quadricUpdateAttributes(Quadric& Q, const Vector3& p0, const Vector3
- }
- #endif
-
--static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap)
-+static void fillFaceQuadrics(Quadric* vertex_quadrics, Quadric* vertex_no_attrib_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap)
- {
- for (size_t i = 0; i < index_count; i += 3)
- {
-@@ -703,6 +732,9 @@ static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
-
- Quadric Q;
- quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], 1.f);
-+ quadricAdd(vertex_no_attrib_quadrics[remap[i0]], Q);
-+ quadricAdd(vertex_no_attrib_quadrics[remap[i1]], Q);
-+ quadricAdd(vertex_no_attrib_quadrics[remap[i2]], Q);
-
- #if ATTRIBUTES
- quadricUpdateAttributes(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], Q.w);
-@@ -713,7 +745,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, const unsigned int* loopback)
-+static void fillEdgeQuadrics(Quadric* vertex_quadrics, Quadric* vertex_no_attrib_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)
- {
-@@ -757,6 +789,9 @@ static void fillEdgeQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
-
- quadricAdd(vertex_quadrics[remap[i0]], Q);
- quadricAdd(vertex_quadrics[remap[i1]], Q);
-+
-+ quadricAdd(vertex_no_attrib_quadrics[remap[i0]], Q);
-+ quadricAdd(vertex_no_attrib_quadrics[remap[i1]], Q);
- }
- }
- }
-@@ -861,7 +896,7 @@ static size_t pickEdgeCollapses(Collapse* collapses, const unsigned int* indices
- return collapse_count;
- }
-
--static void rankEdgeCollapses(Collapse* collapses, size_t collapse_count, const Vector3* vertex_positions, const Quadric* vertex_quadrics, const unsigned int* remap)
-+static void rankEdgeCollapses(Collapse* collapses, size_t collapse_count, const Vector3* vertex_positions, const Quadric* vertex_quadrics, const Quadric* vertex_no_attrib_quadrics, const unsigned int* remap)
- {
- for (size_t i = 0; i < collapse_count; ++i)
- {
-@@ -881,10 +916,14 @@ static void rankEdgeCollapses(Collapse* collapses, size_t collapse_count, const
- float ei = quadricError(qi, vertex_positions[i1]);
- float ej = quadricError(qj, vertex_positions[j1]);
-
-+ const Quadric& naqi = vertex_no_attrib_quadrics[remap[i0]];
-+ const Quadric& naqj = vertex_no_attrib_quadrics[remap[j0]];
-+
- // pick edge direction with minimal error
- c.v0 = ei <= ej ? i0 : j0;
- c.v1 = ei <= ej ? i1 : j1;
- c.error = ei <= ej ? ei : ej;
-+ c.distance_error = ei <= ej ? quadricErrorNoAttributes(naqi, vertex_positions[i1]) : quadricErrorNoAttributes(naqj, vertex_positions[j1]);
- }
- }
-
-@@ -981,7 +1020,7 @@ static void sortEdgeCollapses(unsigned int* sort_order, const Collapse* collapse
- }
- }
-
--static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char* collapse_locked, Quadric* vertex_quadrics, const Collapse* collapses, size_t collapse_count, const unsigned int* collapse_order, const unsigned int* remap, const unsigned int* wedge, const unsigned char* vertex_kind, const Vector3* vertex_positions, const EdgeAdjacency& adjacency, size_t triangle_collapse_goal, float error_limit, float& result_error)
-+static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char* collapse_locked, Quadric* vertex_quadrics, Quadric* vertex_no_attrib_quadrics, const Collapse* collapses, size_t collapse_count, const unsigned int* collapse_order, const unsigned int* remap, const unsigned int* wedge, const unsigned char* vertex_kind, const Vector3* vertex_positions, const EdgeAdjacency& adjacency, size_t triangle_collapse_goal, float error_limit, float& result_error)
- {
- size_t edge_collapses = 0;
- size_t triangle_collapses = 0;
-@@ -1043,6 +1082,7 @@ static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char*
- assert(collapse_remap[r1] == r1);
-
- quadricAdd(vertex_quadrics[r1], vertex_quadrics[r0]);
-+ quadricAdd(vertex_no_attrib_quadrics[r1], vertex_no_attrib_quadrics[r0]);
-
- if (vertex_kind[i0] == Kind_Complex)
- {
-@@ -1080,7 +1120,7 @@ static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char*
- triangle_collapses += (vertex_kind[i0] == Kind_Border) ? 1 : 2;
- edge_collapses++;
-
-- result_error = result_error < c.error ? c.error : result_error;
-+ result_error = result_error < c.distance_error ? c.distance_error : result_error;
- }
-
- #if TRACE
-@@ -1469,9 +1509,11 @@ size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned
-
- Quadric* vertex_quadrics = allocator.allocate<Quadric>(vertex_count);
- memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric));
-+ Quadric* vertex_no_attrib_quadrics = allocator.allocate<Quadric>(vertex_count);
-+ memset(vertex_no_attrib_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, loopback);
-+ fillFaceQuadrics(vertex_quadrics, vertex_no_attrib_quadrics, indices, index_count, vertex_positions, remap);
-+ fillEdgeQuadrics(vertex_quadrics, vertex_no_attrib_quadrics, indices, index_count, vertex_positions, remap, vertex_kind, loop, loopback);
-
- if (result != indices)
- memcpy(result, indices, index_count * sizeof(unsigned int));
-@@ -1502,7 +1544,7 @@ size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned
- if (edge_collapse_count == 0)
- break;
-
-- rankEdgeCollapses(edge_collapses, edge_collapse_count, vertex_positions, vertex_quadrics, remap);
-+ rankEdgeCollapses(edge_collapses, edge_collapse_count, vertex_positions, vertex_quadrics, vertex_no_attrib_quadrics, remap);
-
- #if TRACE > 1
- dumpEdgeCollapses(edge_collapses, edge_collapse_count, vertex_kind);
-@@ -1521,7 +1563,7 @@ size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned
- printf("pass %d: ", int(pass_count++));
- #endif
-
-- size_t collapses = performEdgeCollapses(collapse_remap, collapse_locked, vertex_quadrics, edge_collapses, edge_collapse_count, collapse_order, remap, wedge, vertex_kind, vertex_positions, adjacency, triangle_collapse_goal, error_limit, result_error);
-+ size_t collapses = performEdgeCollapses(collapse_remap, collapse_locked, vertex_quadrics, vertex_no_attrib_quadrics, edge_collapses, edge_collapse_count, collapse_order, remap, wedge, vertex_kind, vertex_positions, adjacency, triangle_collapse_goal, error_limit, result_error);
-
- // no edges can be collapsed any more due to hitting the error limit or triangle collapse limit
- if (collapses == 0)
diff --git a/thirdparty/meshoptimizer/patches/attribute-aware-simplify.patch b/thirdparty/meshoptimizer/patches/attribute-aware-simplify.patch
deleted file mode 100644
index c065026a7d..0000000000
--- a/thirdparty/meshoptimizer/patches/attribute-aware-simplify.patch
+++ /dev/null
@@ -1,263 +0,0 @@
-diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h
-index d95725dd71..46d28d3ea3 100644
---- a/thirdparty/meshoptimizer/meshoptimizer.h
-+++ b/thirdparty/meshoptimizer/meshoptimizer.h
-@@ -321,6 +321,11 @@ enum
- meshopt_SimplifyLockBorder = 1 << 0,
- };
-
-+/**
-+ * Experimental: Mesh simplifier with attribute metric; attributes follow xyz position data atm (vertex data must contain 3 + attribute_count floats per vertex)
-+ */
-+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, unsigned int options, float* result_error, const float* attributes, const float* attribute_weights, size_t attribute_count);
-+
- /**
- * Mesh simplifier
- * Reduces the number of triangles in the mesh, attempting to preserve mesh appearance as much as possible
-diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
-index 5f0e9bac31..797329b010 100644
---- a/thirdparty/meshoptimizer/simplifier.cpp
-+++ b/thirdparty/meshoptimizer/simplifier.cpp
-@@ -20,6 +20,8 @@
- #define TRACESTATS(i) (void)0
- #endif
-
-+#define ATTRIBUTES 8
-+
- // This work is based on:
- // Michael Garland and Paul S. Heckbert. Surface simplification using quadric error metrics. 1997
- // Michael Garland. Quadric-based polygonal surface simplification. 1999
-@@ -376,6 +378,10 @@ static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned
- struct Vector3
- {
- float x, y, z;
-+
-+#if ATTRIBUTES
-+ float a[ATTRIBUTES];
-+#endif
- };
-
- static float rescalePositions(Vector3* result, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride)
-@@ -432,6 +438,13 @@ struct Quadric
- float a10, a20, a21;
- float b0, b1, b2, c;
- float w;
-+
-+#if ATTRIBUTES
-+ float gx[ATTRIBUTES];
-+ float gy[ATTRIBUTES];
-+ float gz[ATTRIBUTES];
-+ float gw[ATTRIBUTES];
-+#endif
- };
-
- struct Collapse
-@@ -474,6 +487,16 @@ static void quadricAdd(Quadric& Q, const Quadric& R)
- Q.b2 += R.b2;
- Q.c += R.c;
- Q.w += R.w;
-+
-+#if ATTRIBUTES
-+ for (int k = 0; k < ATTRIBUTES; ++k)
-+ {
-+ Q.gx[k] += R.gx[k];
-+ Q.gy[k] += R.gy[k];
-+ Q.gz[k] += R.gz[k];
-+ Q.gw[k] += R.gw[k];
-+ }
-+#endif
- }
-
- static float quadricError(const Quadric& Q, const Vector3& v)
-@@ -499,6 +522,17 @@ static float quadricError(const Quadric& Q, const Vector3& v)
- r += ry * v.y;
- r += rz * v.z;
-
-+#if ATTRIBUTES
-+ // see quadricUpdateAttributes for general derivation; here we need to add the parts of (eval(pos) - attr)^2 that depend on attr
-+ for (int k = 0; k < ATTRIBUTES; ++k)
-+ {
-+ float a = v.a[k];
-+
-+ r += a * a * Q.w;
-+ r -= 2 * a * (v.x * Q.gx[k] + v.y * Q.gy[k] + v.z * Q.gz[k] + Q.gw[k]);
-+ }
-+#endif
-+
- float s = Q.w == 0.f ? 0.f : 1.f / Q.w;
-
- return fabsf(r) * s;
-@@ -522,6 +556,13 @@ static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d, flo
- Q.b2 = c * dw;
- Q.c = d * dw;
- Q.w = w;
-+
-+#if ATTRIBUTES
-+ memset(Q.gx, 0, sizeof(Q.gx));
-+ memset(Q.gy, 0, sizeof(Q.gy));
-+ memset(Q.gz, 0, sizeof(Q.gz));
-+ memset(Q.gw, 0, sizeof(Q.gw));
-+#endif
- }
-
- static void quadricFromPoint(Quadric& Q, float x, float y, float z, float w)
-@@ -574,6 +615,84 @@ static void quadricFromTriangleEdge(Quadric& Q, const Vector3& p0, const Vector3
- quadricFromPlane(Q, normal.x, normal.y, normal.z, -distance, length * weight);
- }
-
-+#if ATTRIBUTES
-+static void quadricUpdateAttributes(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2, float w)
-+{
-+ // for each attribute we want to encode the following function into the quadric:
-+ // (eval(pos) - attr)^2
-+ // where eval(pos) interpolates attribute across the triangle like so:
-+ // eval(pos) = pos.x * gx + pos.y * gy + pos.z * gz + gw
-+ // where gx/gy/gz/gw are gradients
-+ Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z};
-+ Vector3 p20 = {p2.x - p0.x, p2.y - p0.y, p2.z - p0.z};
-+
-+ // we compute gradients using barycentric coordinates; barycentric coordinates can be computed as follows:
-+ // v = (d11 * d20 - d01 * d21) / denom
-+ // w = (d00 * d21 - d01 * d20) / denom
-+ // u = 1 - v - w
-+ // here v0, v1 are triangle edge vectors, v2 is a vector from point to triangle corner, and dij = dot(vi, vj)
-+ const Vector3& v0 = p10;
-+ const Vector3& v1 = p20;
-+ float d00 = v0.x * v0.x + v0.y * v0.y + v0.z * v0.z;
-+ float d01 = v0.x * v1.x + v0.y * v1.y + v0.z * v1.z;
-+ float d11 = v1.x * v1.x + v1.y * v1.y + v1.z * v1.z;
-+ float denom = d00 * d11 - d01 * d01;
-+ float denomr = denom == 0 ? 0.f : 1.f / denom;
-+
-+ // precompute gradient factors
-+ // these are derived by directly computing derivative of eval(pos) = a0 * u + a1 * v + a2 * w and factoring out common factors that are shared between attributes
-+ float gx1 = (d11 * v0.x - d01 * v1.x) * denomr;
-+ float gx2 = (d00 * v1.x - d01 * v0.x) * denomr;
-+ float gy1 = (d11 * v0.y - d01 * v1.y) * denomr;
-+ float gy2 = (d00 * v1.y - d01 * v0.y) * denomr;
-+ float gz1 = (d11 * v0.z - d01 * v1.z) * denomr;
-+ float gz2 = (d00 * v1.z - d01 * v0.z) * denomr;
-+
-+ for (int k = 0; k < ATTRIBUTES; ++k)
-+ {
-+ float a0 = p0.a[k], a1 = p1.a[k], a2 = p2.a[k];
-+
-+ // compute gradient of eval(pos) for x/y/z/w
-+ // the formulas below are obtained by directly computing derivative of eval(pos) = a0 * u + a1 * v + a2 * w
-+ float gx = gx1 * (a1 - a0) + gx2 * (a2 - a0);
-+ float gy = gy1 * (a1 - a0) + gy2 * (a2 - a0);
-+ float gz = gz1 * (a1 - a0) + gz2 * (a2 - a0);
-+ float gw = a0 - p0.x * gx - p0.y * gy - p0.z * gz;
-+
-+ // quadric encodes (eval(pos)-attr)^2; this means that the resulting expansion needs to compute, for example, pos.x * pos.y * K
-+ // since quadrics already encode factors for pos.x * pos.y, we can accumulate almost everything in basic quadric fields
-+ Q.a00 += w * (gx * gx);
-+ Q.a11 += w * (gy * gy);
-+ Q.a22 += w * (gz * gz);
-+
-+ Q.a10 += w * (gy * gx);
-+ Q.a20 += w * (gz * gx);
-+ Q.a21 += w * (gz * gy);
-+
-+ Q.b0 += w * (gx * gw);
-+ Q.b1 += w * (gy * gw);
-+ Q.b2 += w * (gz * gw);
-+
-+ Q.c += w * (gw * gw);
-+
-+ // the only remaining sum components are ones that depend on attr; these will be addded during error evaluation, see quadricError
-+ Q.gx[k] = w * gx;
-+ Q.gy[k] = w * gy;
-+ Q.gz[k] = w * gz;
-+ Q.gw[k] = w * gw;
-+
-+#if TRACE > 2
-+ printf("attr%d: %e %e %e\n",
-+ k,
-+ (gx * p0.x + gy * p0.y + gz * p0.z + gw - a0),
-+ (gx * p1.x + gy * p1.y + gz * p1.z + gw - a1),
-+ (gx * p2.x + gy * p2.y + gz * p2.z + gw - a2)
-+ );
-+#endif
-+ }
-+}
-+#endif
-+
- static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap)
- {
- for (size_t i = 0; i < index_count; i += 3)
-@@ -585,6 +704,9 @@ static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
- Quadric Q;
- quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], 1.f);
-
-+#if ATTRIBUTES
-+ quadricUpdateAttributes(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], Q.w);
-+#endif
- quadricAdd(vertex_quadrics[remap[i0]], Q);
- quadricAdd(vertex_quadrics[remap[i1]], Q);
- quadricAdd(vertex_quadrics[remap[i2]], Q);
-@@ -1278,14 +1400,20 @@ MESHOPTIMIZER_API 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, unsigned int options, float* out_result_error)
-+{
-+ return meshopt_simplifyWithAttributes(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, target_index_count, target_error, options, out_result_error, 0, 0, 0);
-+}
-+
-+size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, unsigned int options, float* out_result_error, const float* attributes, const float* attribute_weights, size_t attribute_count)
- {
- using namespace meshopt;
-
- assert(index_count % 3 == 0);
-- assert(vertex_positions_stride >= 12 && vertex_positions_stride <= 256);
-- assert(vertex_positions_stride % sizeof(float) == 0);
-+ assert(vertex_stride >= 12 && vertex_stride <= 256);
-+ assert(vertex_stride % sizeof(float) == 0);
- assert(target_index_count <= index_count);
- assert((options & ~(meshopt_SimplifyLockBorder)) == 0);
-+ assert(attribute_count <= ATTRIBUTES);
-
- meshopt_Allocator allocator;
-
-@@ -1299,7 +1427,7 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
- // build position remap that maps each vertex to the one with identical position
- unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
- unsigned int* wedge = allocator.allocate<unsigned int>(vertex_count);
-- buildPositionRemap(remap, wedge, vertex_positions_data, vertex_count, vertex_positions_stride, allocator);
-+ buildPositionRemap(remap, wedge, vertex_data, vertex_count, vertex_stride, allocator);
-
- // classify vertices; vertex kind determines collapse rules, see kCanCollapse
- unsigned char* vertex_kind = allocator.allocate<unsigned char>(vertex_count);
-@@ -1323,7 +1451,21 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
- #endif
-
- Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
-- rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride);
-+ rescalePositions(vertex_positions, vertex_data, vertex_count, vertex_stride);
-+
-+#if ATTRIBUTES
-+ for (size_t i = 0; i < vertex_count; ++i)
-+ {
-+ memset(vertex_positions[i].a, 0, sizeof(vertex_positions[i].a));
-+
-+ for (size_t k = 0; k < attribute_count; ++k)
-+ {
-+ float a = attributes[i * attribute_count + k];
-+
-+ vertex_positions[i].a[k] = a * attribute_weights[k];
-+ }
-+ }
-+#endif
-
- Quadric* vertex_quadrics = allocator.allocate<Quadric>(vertex_count);
- memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric));
-@@ -1415,7 +1557,9 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
-
- // result_error is quadratic; we need to remap it back to linear
- if (out_result_error)
-+ {
- *out_result_error = sqrtf(result_error);
-+ }
-
- return result_count;
- }
diff --git a/thirdparty/meshoptimizer/patches/distance-only-metric.patch b/thirdparty/meshoptimizer/patches/distance-only-metric.patch
new file mode 100644
index 0000000000..651bdba5ef
--- /dev/null
+++ b/thirdparty/meshoptimizer/patches/distance-only-metric.patch
@@ -0,0 +1,39 @@
+diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
+index 5ba8570076..6f8b0e520e 100644
+--- a/thirdparty/meshoptimizer/simplifier.cpp
++++ b/thirdparty/meshoptimizer/simplifier.cpp
+@@ -476,6 +476,8 @@ struct Collapse
+ float error;
+ unsigned int errorui;
+ };
++
++ float distance_error;
+ };
+
+ static float normalize(Vector3& v)
+@@ -941,6 +943,8 @@ static void rankEdgeCollapses(Collapse* collapses, size_t collapse_count, const
+ float ei = quadricError(vertex_quadrics[remap[i0]], vertex_positions[i1]);
+ float ej = quadricError(vertex_quadrics[remap[j0]], vertex_positions[j1]);
+
++ float dei = ei, dej = ej;
++
+ if (attribute_count)
+ {
+ ei += quadricError(attribute_quadrics[remap[i0]], &attribute_gradients[remap[i0] * attribute_count], attribute_count, vertex_positions[i1], &vertex_attributes[i1 * attribute_count]);
+@@ -951,6 +955,7 @@ static void rankEdgeCollapses(Collapse* collapses, size_t collapse_count, const
+ c.v0 = ei <= ej ? i0 : j0;
+ c.v1 = ei <= ej ? i1 : j1;
+ c.error = ei <= ej ? ei : ej;
++ c.distance_error = ei <= ej ? dei : dej;
+ }
+ }
+
+@@ -1097,7 +1102,7 @@ static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char*
+ triangle_collapses += (vertex_kind[i0] == Kind_Border) ? 1 : 2;
+ edge_collapses++;
+
+- result_error = result_error < c.error ? c.error : result_error;
++ result_error = result_error < c.distance_error ? c.distance_error : result_error;
+ }
+
+ #if TRACE