Skip to content

Commit fdd22f8

Browse files
authored
Merge pull request #854 from zeux/meshlet-max
clusterizer: Increase max vertex limit to 256
2 parents f50be39 + 18cad7d commit fdd22f8

7 files changed

+88
-41
lines changed

demo/tests.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,52 @@ static void meshletsFlex()
12031203
assert(ml[1].vertex_count == 4);
12041204
}
12051205

1206+
static void meshletsMax()
1207+
{
1208+
float vb[16 * 16 * 3];
1209+
unsigned int ib[15 * 15 * 2 * 3];
1210+
1211+
// 16x16 grid of vertices, 15x15 grid of triangles
1212+
for (int y = 0; y < 16; ++y)
1213+
for (int x = 0; x < 16; ++x)
1214+
{
1215+
vb[(y * 16 + x) * 3 + 0] = float(x);
1216+
vb[(y * 16 + x) * 3 + 1] = float(y);
1217+
vb[(y * 16 + x) * 3 + 2] = 0;
1218+
}
1219+
1220+
for (int y = 0; y < 15; ++y)
1221+
for (int x = 0; x < 15; ++x)
1222+
{
1223+
ib[(y * 15 + x) * 2 * 3 + 0] = (y + 0) * 16 + (x + 0);
1224+
ib[(y * 15 + x) * 2 * 3 + 1] = (y + 0) * 16 + (x + 1);
1225+
ib[(y * 15 + x) * 2 * 3 + 2] = (y + 1) * 16 + (x + 0);
1226+
ib[(y * 15 + x) * 2 * 3 + 3] = (y + 1) * 16 + (x + 0);
1227+
ib[(y * 15 + x) * 2 * 3 + 4] = (y + 0) * 16 + (x + 1);
1228+
ib[(y * 15 + x) * 2 * 3 + 5] = (y + 1) * 16 + (x + 1);
1229+
}
1230+
1231+
meshopt_Meshlet ml[1];
1232+
unsigned int mv[16 * 16];
1233+
unsigned char mt[15 * 15 * 2 * 3 + 3];
1234+
1235+
size_t mc = meshopt_buildMeshlets(ml, mv, mt, ib, sizeof(ib) / sizeof(ib[0]), vb, 16 * 16, sizeof(float) * 3, 256, 512, 0.f);
1236+
assert(mc == 1);
1237+
assert(ml[0].triangle_count == 450);
1238+
assert(ml[0].vertex_count == 256);
1239+
1240+
meshopt_optimizeMeshlet(mv, mt, ml[0].triangle_count, ml[0].vertex_count);
1241+
1242+
// check sequential ordering of remapped indices
1243+
int vmax = -1;
1244+
1245+
for (size_t i = 0; i < 450 * 3; ++i)
1246+
{
1247+
assert(mt[i] <= vmax + 1);
1248+
vmax = vmax < mt[i] ? mt[i] : vmax;
1249+
}
1250+
}
1251+
12061252
static void partitionBasic()
12071253
{
12081254
// 0 1 2
@@ -2292,6 +2338,7 @@ void runTests()
22922338
meshletsDense();
22932339
meshletsSparse();
22942340
meshletsFlex();
2341+
meshletsMax();
22952342

22962343
partitionBasic();
22972344

js/meshopt_clusterizer.js

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

js/meshopt_clusterizer.module.js

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

js/meshopt_encoder.js

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

js/meshopt_encoder.module.js

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

src/clusterizer.cpp

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
namespace meshopt
1414
{
1515

16-
// This must be <= 255 since index 0xff is used internally to indice a vertex that doesn't belong to a meshlet
17-
const size_t kMeshletMaxVertices = 255;
16+
// This must be <= 256 since meshlet indices are stored as bytes
17+
const size_t kMeshletMaxVertices = 256;
1818

1919
// A reasonable limit is around 2*max_vertices or less
2020
const size_t kMeshletMaxTriangles = 512;
@@ -328,22 +328,22 @@ static void finishMeshlet(meshopt_Meshlet& meshlet, unsigned char* meshlet_trian
328328
meshlet_triangles[offset++] = 0;
329329
}
330330

331-
static bool appendMeshlet(meshopt_Meshlet& meshlet, unsigned int a, unsigned int b, unsigned int c, unsigned char* used, meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, size_t meshlet_offset, size_t max_vertices, size_t max_triangles, bool split = false)
331+
static bool appendMeshlet(meshopt_Meshlet& meshlet, unsigned int a, unsigned int b, unsigned int c, short* used, meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, size_t meshlet_offset, size_t max_vertices, size_t max_triangles, bool split = false)
332332
{
333-
unsigned char& av = used[a];
334-
unsigned char& bv = used[b];
335-
unsigned char& cv = used[c];
333+
short& av = used[a];
334+
short& bv = used[b];
335+
short& cv = used[c];
336336

337337
bool result = false;
338338

339-
int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff);
339+
int used_extra = (av < 0) + (bv < 0) + (cv < 0);
340340

341341
if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles || split)
342342
{
343343
meshlets[meshlet_offset] = meshlet;
344344

345345
for (size_t j = 0; j < meshlet.vertex_count; ++j)
346-
used[meshlet_vertices[meshlet.vertex_offset + j]] = 0xff;
346+
used[meshlet_vertices[meshlet.vertex_offset + j]] = -1;
347347

348348
finishMeshlet(meshlet, meshlet_triangles);
349349

@@ -355,33 +355,33 @@ static bool appendMeshlet(meshopt_Meshlet& meshlet, unsigned int a, unsigned int
355355
result = true;
356356
}
357357

358-
if (av == 0xff)
358+
if (av < 0)
359359
{
360-
av = (unsigned char)meshlet.vertex_count;
360+
av = short(meshlet.vertex_count);
361361
meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = a;
362362
}
363363

364-
if (bv == 0xff)
364+
if (bv < 0)
365365
{
366-
bv = (unsigned char)meshlet.vertex_count;
366+
bv = short(meshlet.vertex_count);
367367
meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = b;
368368
}
369369

370-
if (cv == 0xff)
370+
if (cv < 0)
371371
{
372-
cv = (unsigned char)meshlet.vertex_count;
372+
cv = short(meshlet.vertex_count);
373373
meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = c;
374374
}
375375

376-
meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 0] = av;
377-
meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 1] = bv;
378-
meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 2] = cv;
376+
meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 0] = (unsigned char)av;
377+
meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 1] = (unsigned char)bv;
378+
meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 2] = (unsigned char)cv;
379379
meshlet.triangle_count++;
380380

381381
return result;
382382
}
383383

384-
static unsigned int getNeighborTriangle(const meshopt_Meshlet& meshlet, const Cone& meshlet_cone, const 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)
384+
static unsigned int getNeighborTriangle(const meshopt_Meshlet& meshlet, const Cone& meshlet_cone, const unsigned int* meshlet_vertices, const unsigned int* indices, const TriangleAdjacency2& adjacency, const Cone* triangles, const unsigned int* live_triangles, const short* used, float meshlet_expected_radius, float cone_weight)
385385
{
386386
unsigned int best_triangle = ~0u;
387387
int best_priority = 5;
@@ -399,7 +399,7 @@ static unsigned int getNeighborTriangle(const meshopt_Meshlet& meshlet, const Co
399399
unsigned int triangle = neighbors[j];
400400
unsigned int a = indices[triangle * 3 + 0], b = indices[triangle * 3 + 1], c = indices[triangle * 3 + 2];
401401

402-
int extra = (used[a] == 0xff) + (used[b] == 0xff) + (used[c] == 0xff);
402+
int extra = (used[a] < 0) + (used[b] < 0) + (used[c] < 0);
403403
assert(extra <= 2);
404404

405405
int priority = -1;
@@ -785,9 +785,9 @@ size_t meshopt_buildMeshletsFlex(meshopt_Meshlet* meshlets, unsigned int* meshle
785785
cornerz = cornerz > tri.pz ? tri.pz : cornerz;
786786
}
787787

788-
// index of the vertex in the meshlet, 0xff if the vertex isn't used
789-
unsigned char* used = allocator.allocate<unsigned char>(vertex_count);
790-
memset(used, -1, vertex_count);
788+
// index of the vertex in the meshlet, -1 if the vertex isn't used
789+
short* used = allocator.allocate<short>(vertex_count);
790+
memset(used, -1, vertex_count * sizeof(short));
791791

792792
// initial seed triangle is the one closest to the corner
793793
unsigned int initial_seed = ~0u;
@@ -846,7 +846,7 @@ size_t meshopt_buildMeshletsFlex(meshopt_Meshlet* meshlets, unsigned int* meshle
846846
if (best_triangle == ~0u)
847847
break;
848848

849-
int best_extra = (used[indices[best_triangle * 3 + 0]] == 0xff) + (used[indices[best_triangle * 3 + 1]] == 0xff) + (used[indices[best_triangle * 3 + 2]] == 0xff);
849+
int best_extra = (used[indices[best_triangle * 3 + 0]] < 0) + (used[indices[best_triangle * 3 + 1]] < 0) + (used[indices[best_triangle * 3 + 2]] < 0);
850850

851851
// if the best triangle doesn't fit into current meshlet, we re-select using seeds to maintain global flow
852852
if (split || (meshlet.vertex_count + best_extra > max_vertices || meshlet.triangle_count >= max_triangles))
@@ -936,9 +936,9 @@ size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int* meshle
936936

937937
meshopt_Allocator allocator;
938938

939-
// index of the vertex in the meshlet, 0xff if the vertex isn't used
940-
unsigned char* used = allocator.allocate<unsigned char>(vertex_count);
941-
memset(used, -1, vertex_count);
939+
// index of the vertex in the meshlet, -1 if the vertex isn't used
940+
short* used = allocator.allocate<short>(vertex_count);
941+
memset(used, -1, vertex_count * sizeof(short));
942942

943943
meshopt_Meshlet meshlet = {};
944944
size_t meshlet_offset = 0;
@@ -1233,23 +1233,23 @@ void meshopt_optimizeMeshlet(unsigned int* meshlet_vertices, unsigned char* mesh
12331233
// reorder meshlet vertices for access locality assuming index buffer is scanned sequentially
12341234
unsigned int order[kMeshletMaxVertices];
12351235

1236-
unsigned char remap[kMeshletMaxVertices];
1237-
memset(remap, -1, vertex_count);
1236+
short remap[kMeshletMaxVertices];
1237+
memset(remap, -1, vertex_count * sizeof(short));
12381238

12391239
size_t vertex_offset = 0;
12401240

12411241
for (size_t i = 0; i < triangle_count * 3; ++i)
12421242
{
1243-
unsigned char& r = remap[indices[i]];
1243+
short& r = remap[indices[i]];
12441244

1245-
if (r == 0xff)
1245+
if (r < 0)
12461246
{
1247-
r = (unsigned char)(vertex_offset);
1247+
r = short(vertex_offset);
12481248
order[vertex_offset] = vertices[indices[i]];
12491249
vertex_offset++;
12501250
}
12511251

1252-
indices[i] = r;
1252+
indices[i] = (unsigned char)r;
12531253
}
12541254

12551255
assert(vertex_offset <= vertex_count);

src/meshoptimizer.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ struct meshopt_Meshlet
544544
* meshlet_vertices must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_vertices
545545
* meshlet_triangles must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_triangles * 3
546546
* vertex_positions should have float3 position in the first 12 bytes of each vertex
547-
* max_vertices and max_triangles must not exceed implementation limits (max_vertices <= 255 - not 256!, max_triangles <= 512; max_triangles must be divisible by 4)
547+
* max_vertices and max_triangles must not exceed implementation limits (max_vertices <= 256, max_triangles <= 512; max_triangles must be divisible by 4)
548548
* cone_weight should be set to 0 when cone culling is not used, and a value between 0 and 1 otherwise to balance between cluster size and cone culling efficiency
549549
*/
550550
MESHOPTIMIZER_API size_t meshopt_buildMeshlets(struct meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight);
@@ -561,7 +561,7 @@ MESHOPTIMIZER_API size_t meshopt_buildMeshletsBound(size_t index_count, size_t m
561561
* meshlet_vertices must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_vertices
562562
* meshlet_triangles must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_triangles * 3
563563
* vertex_positions should have float3 position in the first 12 bytes of each vertex
564-
* max_vertices, min_triangles and max_triangles must not exceed implementation limits (max_vertices <= 255 - not 256!, max_triangles <= 512; min_triangles <= max_triangles; both min_triangles and max_triangles must be divisible by 4)
564+
* max_vertices, min_triangles and max_triangles must not exceed implementation limits (max_vertices <= 256, max_triangles <= 512; min_triangles <= max_triangles; both min_triangles and max_triangles must be divisible by 4)
565565
* cone_weight should be set to 0 when cone culling is not used, and a value between 0 and 1 otherwise to balance between cluster size and cone culling efficiency; additionally, cone_weight can be set to a negative value to prioritize axis aligned clusters (for raytracing) instead
566566
* split_factor should be set to a non-negative value; when greater than 0, clusters that have large bounds may be split unless they are under the min_triangles threshold
567567
*/
@@ -573,7 +573,7 @@ MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshletsFlex(struct meshopt_Meshl
573573
*
574574
* meshlet_triangles and meshlet_vertices must refer to meshlet triangle and vertex index data; when buildMeshlets* is used, these
575575
* need to be computed from meshlet's vertex_offset and triangle_offset
576-
* triangle_count and vertex_count must not exceed implementation limits (vertex_count <= 255 - not 256!, triangle_count <= 512)
576+
* triangle_count and vertex_count must not exceed implementation limits (vertex_count <= 256, triangle_count <= 512)
577577
*/
578578
MESHOPTIMIZER_API void meshopt_optimizeMeshlet(unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, size_t triangle_count, size_t vertex_count);
579579

0 commit comments

Comments
 (0)