# Using Meshoptimizer Library to merge meshlets and simplify their geometry

After reading a paper and watchind some videos about nanite I decided to try (Doing my best…) to implement an hierarchical LODs rendering using mesh shaders. I’m using Zeux’s library Meshoptmizer(GitHub - zeux/meshoptimizer: Mesh optimization library that makes meshes smaller and faster to render) to help me achieve that. The library defines a meshlet as a couple of indexes and counts.

``````struct meshopt_Meshlet
{
/* offsets within meshlet_vertices and meshlet_triangles arrays with meshlet data */
unsigned int vertex_offset;
unsigned int triangle_offset;

/* number of vertices and triangles used in the meshlet; data is stored in consecutive range defined by offset and count */
unsigned int vertex_count;
unsigned int triangle_count;
};
``````

The function meshopt_buildMeshlets outputs an array of meshopt_meshlet 's and the buffers that each meshopt_meshlet indexes into (meshlet_triangles and meshlet_vertices). I would like to know, given this structure, how would I merge two meshletsand then use the method meshopt_simplify to simplify their geometry. All this indexing process is quite complicated for me, I’m trying to think in a way that makes sense and works for me.

``````                Cluster father;
Cluster children1               = active_clusters[neighbor_of_i];
Cluster children2               = active_clusters[i];
father.meshlet.triangle_offset  = min(children1.meshlet.triangle_offset,children2.meshlet.triangle_offset);
father.meshlet.vertex_offset    = min(children1.meshlet.vertex_offset,children2.meshlet.vertex_offset);
father.meshlet.vertex_count     = children1.meshlet.vertex_count + children2.meshlet.vertex_count;
father.meshlet.triangle_count   = children1.meshlet.triangle_count + children2.meshlet.triangle_count;
father.aabb                     = compute_cluster_aabb(vertices,father.meshlet);//Compute AABB
``````

Consider that Cluster has a meshopt_meshlet field.

Could anyone demonstrate to me how do Merge two meshopt_meshlets and simplify their geomtry using meshopt_simplify, I’m not sure about how to properly index the the final vertex/index buffer. This question may be a bit hard for me to properly explain myself, so please let me know what details you need.

1 Like

to use the meshopt_simplify on the merged meshlet, you need to set the offset correctly.
below is my code,it can merge meshlets and simplify it.Hope it will help!

``````static void merge(std::vector<meshopt_Meshlet>& meshlets, std::vector<uint32_t>& index, std::vector<meshopt_Bounds>& meshletBounds, std::vector<uint8_t>vertices, int stride)
{
std::vector<uint32_t>new_index;
std::vector<meshopt_Meshlet>new_meshlets;
std::vector<meshopt_Bounds>new_bound;
std::vector<bool>is_merged(meshlets.size(), false);
auto offset = 0;
for (int cnt = 0; cnt + 1 < meshlets.size(); cnt = cnt + 2)
{
meshopt_Meshlet mt1, mt2;
{
.....
//find mt1,mt2
}
for (int i = 0; i < mt1.triangle_count * 3; i++)
{
new_index.emplace_back(index[mt1.triangle_offset + i]);
}
for (int i = 0; i < mt2.triangle_count * 3; i++)
{
new_index.emplace_back(index[mt2.triangle_offset + i]);
}
meshopt_Meshlet tmp;
tmp.triangle_count = mt1.triangle_count + mt2.triangle_count;
tmp.triangle_offset = offset;
new_meshlets.emplace_back(tmp);
offset = new_index.size();
//
auto p = meshopt_computeClusterBounds(&new_index[tmp.triangle_offset], tmp.triangle_count * 3, (float*)vertices.data(), vertices.size() / stride, stride);
new_bound.emplace_back(p);
//
}
//odd size
if (meshlets.size() % 2 != 0)
{
meshopt_Meshlet last;
for (int id = 0; id < is_merged.size(); id++)
{
if (is_merged[id] == false)
{
last = meshlets[id];
}
}
for (int i = 0; i < last.triangle_count * 3; i++)
{
new_index.emplace_back(index[last.triangle_offset + i]);
}
meshopt_Meshlet tmp;
tmp.triangle_count = last.triangle_count;
tmp.triangle_offset = offset;
new_meshlets.emplace_back(tmp);
offset = new_index.size();
}
meshlets.assign(new_meshlets.begin(), new_meshlets.end());
index.assign(new_index.begin(), new_index.end());
//simplify meshlets
for (int i = 0; i < meshlets.size(); i++)
{
auto& mt = meshlets[i];
float target_error = 0.9;
float lod_error = 0.f;
auto n = meshopt_simplify(&index[mt.triangle_offset], &index[mt.triangle_offset], mt.triangle_count * 3, (float*)vertices.data(), vertices.size() / stride, stride,
6, target_error, 1, &lod_error);
mt.triangle_count = n / 3;
}
//recalculate the bounds
for (int i = 0; i < meshlets.size(); i++)
{
auto tmp = meshlets[i];
auto p = meshopt_computeClusterBounds(&new_index[tmp.triangle_offset], tmp.triangle_count * 3, (float*)vertices.data(), vertices.size() / stride, stride);
new_bound.emplace_back(p);
}
meshletBounds.assign(new_bound.begin(), new_bound.end());

``````
1 Like