I have a setup for rendering models using task/mesh shaders.
First I create an array of meshlets and submit that to the shaders perform culling in task shader, assemble the primitives in the mesh shader etc…
However, I can’t make that work with Models that have more than one primitive. In indexed drawing , for each “submesh” I would call vkdrawindexed(using traditional pipeline input assemble vertex buffer…) using the vertex offset and index base for each primitive and everything would work. However with this extra step of first creating the meshlets things get more complicated.
Should I create the meshlets for each “submesh”, or use all the vertices and indeces for the entire model and create the meshlets with that data. If so, how can I properly render the model in the Mesh shader with all that data. My goal is to render models using vkCmdDrawMeshTasksIndirectEXT .
What exactly is it that’s causing you to have “submeshes”? You say that it’s a different “primitive”, but what do you mean by that? Do you mean that you’re changing from triangle strips to triangle lists? Or do you have different lists of triangles so that you can render only part of the mesh? Or are your meshes composed of a combination of lines and triangles (or points)?
If it’s just strips vs. lists (ie: the same base primitive of triangles), then you should make everything an optimized triangle list and thereby avoid the problem. If it’s just different lists so that you can render segments of them separately, then whatever lists you’re trying to render at the same time should all be part of the same set of tasks. And if it’s different base primitives, that’s a more complicated matter.
The thing about task/mesh shaders is that you build them more-or-less however you want. This means that there’s no one-size-fits-all solution; you have to look at your particular needs to know what to do. And we need more information to know what those needs are.
Alfonse by submesh I mean a part of a model. A complex model composed of several parts.
In assimp library it’s something like
const aiScene* assimp_scene= importer.ReadFile(…)
auto number_of_meshes = assimp_scene->mNumMeshes //(Each single part of a complex model)
In traditional pipeline I put all the vertices for all the parts of the model into one vertex buffer, and count for the vertex offset and then I can render the entire model using drawIndexed.
uint32_t index_offset = 0;
uint32_t vertex_offset = 0;
for (unsigned int i = 0; i < model.meshes.size(); ++i)
const aiMesh* assimp_mesh = assimpScene->mMeshes[i];
meshes[i].index_offset = index_offset;
meshes[i].vertex_offset = vertex_offset;
meshes[i].index_count = assimp_mesh->mNumFaces * 3;
I get that. My question is why it is “composed of several parts”. What is it about the model that is different between its submodels which necessitates that it be broken up into submodels.
That tells me that there is no difference between them. They are not different primitives. There are no state changes between submodels. Etc.
So what is stopping you from doing the same thing with task/mesh shaders?
Thanks Alfonse, you are correct there is no difference at all. Basically I was having trouble with how to properly index meshlets offsets to meshlet_vertices - to global vertex buffer. Since I’m using a single vertex buffer to all the meshes in a obj file. But a little bit of patience and it worked.