Updated meshoptimizer.

This commit is contained in:
Бранимир Караџић
2025-11-20 09:57:11 -08:00
committed by Branimir Karadžić
parent 0292095363
commit c35f437910
6 changed files with 151 additions and 94 deletions
+64 -26
View File
@@ -620,7 +620,7 @@ static void rescaleAttributes(float* result, const float* vertex_attributes_data
}
}
static void finalizeVertices(float* vertex_positions_data, size_t vertex_positions_stride, float* vertex_attributes_data, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t vertex_count, const Vector3* vertex_positions, const float* vertex_attributes, const unsigned int* sparse_remap, const unsigned int* attribute_remap, float vertex_scale, const float* vertex_offset, const unsigned char* vertex_update)
static void finalizeVertices(float* vertex_positions_data, size_t vertex_positions_stride, float* vertex_attributes_data, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t vertex_count, const Vector3* vertex_positions, const float* vertex_attributes, const unsigned int* sparse_remap, const unsigned int* attribute_remap, float vertex_scale, const float* vertex_offset, const unsigned char* vertex_kind, const unsigned char* vertex_update, const unsigned char* vertex_lock)
{
size_t vertex_positions_stride_float = vertex_positions_stride / sizeof(float);
size_t vertex_attributes_stride_float = vertex_attributes_stride / sizeof(float);
@@ -632,12 +632,20 @@ static void finalizeVertices(float* vertex_positions_data, size_t vertex_positio
unsigned int ri = sparse_remap ? sparse_remap[i] : unsigned(i);
const Vector3& p = vertex_positions[i];
float* v = vertex_positions_data + ri * vertex_positions_stride_float;
// updating externally locked vertices is not allowed
if (vertex_lock && (vertex_lock[ri] & meshopt_SimplifyVertex_Lock) != 0)
continue;
v[0] = p.x * vertex_scale + vertex_offset[0];
v[1] = p.y * vertex_scale + vertex_offset[1];
v[2] = p.z * vertex_scale + vertex_offset[2];
// moving locked vertices may result in floating point drift
if (vertex_kind[i] != Kind_Locked)
{
const Vector3& p = vertex_positions[i];
float* v = vertex_positions_data + ri * vertex_positions_stride_float;
v[0] = p.x * vertex_scale + vertex_offset[0];
v[1] = p.y * vertex_scale + vertex_offset[1];
v[2] = p.z * vertex_scale + vertex_offset[2];
}
if (attribute_count)
{
@@ -1637,10 +1645,10 @@ static void updateQuadrics(const unsigned int* collapse_remap, size_t vertex_cou
}
}
static void solveQuadrics(Vector3* vertex_positions, float* vertex_attributes, size_t vertex_count, const Quadric* vertex_quadrics, const QuadricGrad* volume_gradients, const Quadric* attribute_quadrics, const QuadricGrad* attribute_gradients, size_t attribute_count, const unsigned int* remap, const unsigned int* wedge, const EdgeAdjacency& adjacency, const unsigned char* vertex_kind, const unsigned char* vertex_update)
static void solvePositions(Vector3* vertex_positions, size_t vertex_count, const Quadric* vertex_quadrics, const QuadricGrad* volume_gradients, const Quadric* attribute_quadrics, const QuadricGrad* attribute_gradients, size_t attribute_count, const unsigned int* remap, const unsigned int* wedge, const EdgeAdjacency& adjacency, const unsigned char* vertex_kind, const unsigned char* vertex_update)
{
#if TRACE
size_t stats[5] = {};
size_t stats[6] = {};
#endif
for (size_t i = 0; i < vertex_count; ++i)
@@ -1648,7 +1656,6 @@ static void solveQuadrics(Vector3* vertex_positions, float* vertex_attributes, s
if (!vertex_update[i])
continue;
// moving externally locked vertices is prohibited
// moving vertices on an attribute discontinuity may result in extrapolating UV outside of the chart bounds
// moving vertices on a border requires a stronger edge quadric to preserve the border geometry
if (vertex_kind[i] == Kind_Locked || vertex_kind[i] == Kind_Seam || vertex_kind[i] == Kind_Border)
@@ -1712,36 +1719,64 @@ static void solveQuadrics(Vector3* vertex_positions, float* vertex_attributes, s
continue;
}
// reject updates that increase positional error too much; allow some tolerance to improve attribute quality
if (quadricError(vertex_quadrics[i], p) > quadricError(vertex_quadrics[i], vp) * 1.5f + 1e-6f)
{
TRACESTATS(5);
continue;
}
TRACESTATS(1);
vertex_positions[i] = p;
}
#if TRACE
printf("updated %d/%d positions; failed solve %d bounds %d flip %d\n", int(stats[1]), int(stats[0]), int(stats[2]), int(stats[3]), int(stats[4]));
printf("updated %d/%d positions; failed solve %d bounds %d flip %d error %d\n", int(stats[1]), int(stats[0]), int(stats[2]), int(stats[3]), int(stats[4]), int(stats[5]));
#endif
}
if (attribute_count == 0)
return;
static void solveAttributes(Vector3* vertex_positions, float* vertex_attributes, size_t vertex_count, const Quadric* attribute_quadrics, const QuadricGrad* attribute_gradients, size_t attribute_count, const unsigned int* remap, const unsigned int* wedge, const unsigned char* vertex_kind, const unsigned char* vertex_update)
{
for (size_t i = 0; i < vertex_count; ++i)
{
if (!vertex_update[i])
continue;
// updating externally locked vertices is prohibited
if (vertex_kind[i] == Kind_Locked)
if (remap[i] != i)
continue;
const Vector3& p = vertex_positions[remap[i]];
const Quadric& A = attribute_quadrics[i];
float iw = A.w == 0 ? 0.f : 1.f / A.w;
for (size_t k = 0; k < attribute_count; ++k)
{
const QuadricGrad& G = attribute_gradients[i * attribute_count + k];
unsigned int shared = ~0u;
vertex_attributes[i * attribute_count + k] = (G.gx * p.x + G.gy * p.y + G.gz * p.z + G.gw) * iw;
// for complex vertices, preserve attribute continuity and use highest weight wedge if values were shared
if (vertex_kind[i] == Kind_Complex)
{
shared = unsigned(i);
for (unsigned int v = wedge[i]; v != i; v = wedge[v])
if (vertex_attributes[v * attribute_count + k] != vertex_attributes[i * attribute_count + k])
shared = ~0u;
else if (shared != ~0u && attribute_quadrics[v].w > attribute_quadrics[shared].w)
shared = v;
}
// update attributes for all wedges
unsigned int v = unsigned(i);
do
{
unsigned int r = (shared == ~0u) ? v : shared;
const Vector3& p = vertex_positions[i]; // same for all wedges
const Quadric& A = attribute_quadrics[r];
const QuadricGrad& G = attribute_gradients[r * attribute_count + k];
float iw = A.w == 0 ? 0.f : 1.f / A.w;
float av = (G.gx * p.x + G.gy * p.y + G.gz * p.z + G.gw) * iw;
vertex_attributes[v * attribute_count + k] = av;
v = wedge[v];
} while (v != i);
}
}
}
@@ -2522,16 +2557,19 @@ size_t meshopt_simplifyEdge(unsigned int* destination, const unsigned int* indic
{
unsigned int v = result[i];
// recomputing externally locked vertices may result in floating point drift
vertex_update[v] = vertex_kind[v] != Kind_Locked;
// mark the vertex for finalizeVertices and root vertex for solve*
vertex_update[remap[v]] = vertex_update[v] = 1;
}
// edge adjacency may be stale as we haven't updated it after last series of edge collapses
updateEdgeAdjacency(adjacency, result, result_count, vertex_count, remap);
solveQuadrics(vertex_positions, vertex_attributes, vertex_count, vertex_quadrics, volume_gradients, attribute_quadrics, attribute_gradients, attribute_count, remap, wedge, adjacency, vertex_kind, vertex_update);
solvePositions(vertex_positions, vertex_count, vertex_quadrics, volume_gradients, attribute_quadrics, attribute_gradients, attribute_count, remap, wedge, adjacency, vertex_kind, vertex_update);
finalizeVertices(const_cast<float*>(vertex_positions_data), vertex_positions_stride, const_cast<float*>(vertex_attributes_data), vertex_attributes_stride, attribute_weights, attribute_count, vertex_count, vertex_positions, vertex_attributes, sparse_remap, attribute_remap, vertex_scale, vertex_offset, vertex_update);
if (attribute_count)
solveAttributes(vertex_positions, vertex_attributes, vertex_count, attribute_quadrics, attribute_gradients, attribute_count, remap, wedge, vertex_kind, vertex_update);
finalizeVertices(const_cast<float*>(vertex_positions_data), vertex_positions_stride, const_cast<float*>(vertex_attributes_data), vertex_attributes_stride, attribute_weights, attribute_count, vertex_count, vertex_positions, vertex_attributes, sparse_remap, attribute_remap, vertex_scale, vertex_offset, vertex_kind, vertex_update, vertex_lock);
}
// if debug visualization data is requested, fill it instead of index data; for simplicity, this doesn't work with sparsity