|
@@ -238,7 +238,7 @@ static bool appendMeshlet(meshopt_Meshlet& meshlet, unsigned int a, unsigned int
|
|
|
|
|
|
|
|
bool result = false;
|
|
bool result = false;
|
|
|
|
|
|
|
|
- unsigned int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff);
|
|
|
|
|
|
|
+ int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff);
|
|
|
|
|
|
|
|
if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles)
|
|
if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles)
|
|
|
{
|
|
{
|
|
@@ -283,10 +283,10 @@ static bool appendMeshlet(meshopt_Meshlet& meshlet, unsigned int a, unsigned int
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static unsigned int getNeighborTriangle(const meshopt_Meshlet& meshlet, const Cone* meshlet_cone, unsigned int* meshlet_vertices, const unsigned int* indices, const TriangleAdjacency2& adjacency, const Cone* triangles, const unsigned int* live_triangles, const unsigned char* used, float meshlet_expected_radius, float cone_weight, unsigned int* out_extra)
|
|
|
|
|
|
|
+static unsigned int getNeighborTriangle(const meshopt_Meshlet& meshlet, const Cone* meshlet_cone, unsigned int* meshlet_vertices, const unsigned int* indices, const TriangleAdjacency2& adjacency, const Cone* triangles, const unsigned int* live_triangles, const unsigned char* used, float meshlet_expected_radius, float cone_weight)
|
|
|
{
|
|
{
|
|
|
unsigned int best_triangle = ~0u;
|
|
unsigned int best_triangle = ~0u;
|
|
|
- unsigned int best_extra = 5;
|
|
|
|
|
|
|
+ int best_priority = 5;
|
|
|
float best_score = FLT_MAX;
|
|
float best_score = FLT_MAX;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < meshlet.vertex_count; ++i)
|
|
for (size_t i = 0; i < meshlet.vertex_count; ++i)
|
|
@@ -301,20 +301,26 @@ static unsigned int getNeighborTriangle(const meshopt_Meshlet& meshlet, const Co
|
|
|
unsigned int triangle = neighbors[j];
|
|
unsigned int triangle = neighbors[j];
|
|
|
unsigned int a = indices[triangle * 3 + 0], b = indices[triangle * 3 + 1], c = indices[triangle * 3 + 2];
|
|
unsigned int a = indices[triangle * 3 + 0], b = indices[triangle * 3 + 1], c = indices[triangle * 3 + 2];
|
|
|
|
|
|
|
|
- unsigned int extra = (used[a] == 0xff) + (used[b] == 0xff) + (used[c] == 0xff);
|
|
|
|
|
|
|
+ int extra = (used[a] == 0xff) + (used[b] == 0xff) + (used[c] == 0xff);
|
|
|
|
|
+ assert(extra <= 2);
|
|
|
|
|
|
|
|
- // triangles that don't add new vertices to meshlets are max. priority
|
|
|
|
|
- if (extra != 0)
|
|
|
|
|
- {
|
|
|
|
|
- // artificially increase the priority of dangling triangles as they're expensive to add to new meshlets
|
|
|
|
|
- if (live_triangles[a] == 1 || live_triangles[b] == 1 || live_triangles[c] == 1)
|
|
|
|
|
- extra = 0;
|
|
|
|
|
|
|
+ int priority = -1;
|
|
|
|
|
|
|
|
- extra++;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // triangles that don't add new vertices to meshlets are max. priority
|
|
|
|
|
+ if (extra == 0)
|
|
|
|
|
+ priority = 0;
|
|
|
|
|
+ // artificially increase the priority of dangling triangles as they're expensive to add to new meshlets
|
|
|
|
|
+ else if (live_triangles[a] == 1 || live_triangles[b] == 1 || live_triangles[c] == 1)
|
|
|
|
|
+ priority = 1;
|
|
|
|
|
+ // if two vertices have live count of 2, removing this triangle will make another triangle dangling which is good for overall flow
|
|
|
|
|
+ else if ((live_triangles[a] == 2) + (live_triangles[b] == 2) + (live_triangles[c] == 2) >= 2)
|
|
|
|
|
+ priority = 1 + extra;
|
|
|
|
|
+ // otherwise adjust priority to be after the above cases, 3 or 4 based on used[] count
|
|
|
|
|
+ else
|
|
|
|
|
+ priority = 2 + extra;
|
|
|
|
|
|
|
|
// since topology-based priority is always more important than the score, we can skip scoring in some cases
|
|
// since topology-based priority is always more important than the score, we can skip scoring in some cases
|
|
|
- if (extra > best_extra)
|
|
|
|
|
|
|
+ if (priority > best_priority)
|
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
float score = 0;
|
|
float score = 0;
|
|
@@ -341,18 +347,15 @@ static unsigned int getNeighborTriangle(const meshopt_Meshlet& meshlet, const Co
|
|
|
|
|
|
|
|
// note that topology-based priority is always more important than the score
|
|
// note that topology-based priority is always more important than the score
|
|
|
// this helps maintain reasonable effectiveness of meshlet data and reduces scoring cost
|
|
// this helps maintain reasonable effectiveness of meshlet data and reduces scoring cost
|
|
|
- if (extra < best_extra || score < best_score)
|
|
|
|
|
|
|
+ if (priority < best_priority || score < best_score)
|
|
|
{
|
|
{
|
|
|
best_triangle = triangle;
|
|
best_triangle = triangle;
|
|
|
- best_extra = extra;
|
|
|
|
|
|
|
+ best_priority = priority;
|
|
|
best_score = score;
|
|
best_score = score;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (out_extra)
|
|
|
|
|
- *out_extra = best_extra;
|
|
|
|
|
-
|
|
|
|
|
return best_triangle;
|
|
return best_triangle;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -588,13 +591,13 @@ size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_ve
|
|
|
{
|
|
{
|
|
|
Cone meshlet_cone = getMeshletCone(meshlet_cone_acc, meshlet.triangle_count);
|
|
Cone meshlet_cone = getMeshletCone(meshlet_cone_acc, meshlet.triangle_count);
|
|
|
|
|
|
|
|
- unsigned int best_extra = 0;
|
|
|
|
|
- unsigned int best_triangle = getNeighborTriangle(meshlet, &meshlet_cone, meshlet_vertices, indices, adjacency, triangles, live_triangles, used, meshlet_expected_radius, cone_weight, &best_extra);
|
|
|
|
|
|
|
+ unsigned int best_triangle = getNeighborTriangle(meshlet, &meshlet_cone, meshlet_vertices, indices, adjacency, triangles, live_triangles, used, meshlet_expected_radius, cone_weight);
|
|
|
|
|
+ int best_extra = best_triangle == ~0u ? -1 : (used[indices[best_triangle * 3 + 0]] == 0xff) + (used[indices[best_triangle * 3 + 1]] == 0xff) + (used[indices[best_triangle * 3 + 2]] == 0xff);
|
|
|
|
|
|
|
|
// if the best triangle doesn't fit into current meshlet, the spatial scoring we've used is not very meaningful, so we re-select using topological scoring
|
|
// if the best triangle doesn't fit into current meshlet, the spatial scoring we've used is not very meaningful, so we re-select using topological scoring
|
|
|
if (best_triangle != ~0u && (meshlet.vertex_count + best_extra > max_vertices || meshlet.triangle_count >= max_triangles))
|
|
if (best_triangle != ~0u && (meshlet.vertex_count + best_extra > max_vertices || meshlet.triangle_count >= max_triangles))
|
|
|
{
|
|
{
|
|
|
- best_triangle = getNeighborTriangle(meshlet, NULL, meshlet_vertices, indices, adjacency, triangles, live_triangles, used, meshlet_expected_radius, 0.f, NULL);
|
|
|
|
|
|
|
+ best_triangle = getNeighborTriangle(meshlet, NULL, meshlet_vertices, indices, adjacency, triangles, live_triangles, used, meshlet_expected_radius, 0.f);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// when we run out of neighboring triangles we need to switch to spatial search; we currently just pick the closest triangle irrespective of connectivity
|
|
// when we run out of neighboring triangles we need to switch to spatial search; we currently just pick the closest triangle irrespective of connectivity
|