- Home /
One vertex array per submesh
So I am reading a mesh format that is not supported by unity. But this format handles submeshes a bit different from the unity Mesh class.
The main problem I currently have is that every submesh contains a vertex array and a triangle Array, While unity meshes contains only one Vertex arrays and multiple triangle arrays.
I need help figuring out how to convert this.
Answer by Bunny83 · Nov 12, 2017 at 11:31 PM
Uhm if they are actually seperate meshes you don't want them to have it in one mesh in the first place. A submesh is ment to use a different material and therefore is a seperate drawcall / setpass call. The only point of having submeshes is that they use a shared vertices array.
Of course if you really want to pack them into a single mesh you just need to merge the different vertex arrays into one and adjust the indices for each submesh.
The reason i want this is because this mesh file contains bones, and a skeleton so it will not work if its not packed into one.
I guess ill try to adjust the indices, i tried earlier but failed, so i can try again could you give some hit on how i should approach this?
Why wouldn't it work with bones? If you have several skinned mesh renderer they can all share the same bones. However if you want to merge them just do this:
// pseudo code
List<Vector3> vertices;
foreach submesh do
{
int offset = vertices.Count;
vertices.AddRange(sub$$anonymous$$eshVertices);
foreach submesh index do
index = index + offset
}
So all you have to do is storing the current position in the vertices list as offset. So the first submesh has an offset of 0. So the indices stay the same. The second submesh will start at the end of the first one.
Imagine you would add single quads meshes together. Each quad has 4 vertices and 6 indices. The vertices have the index values "0,1,2,3" and the indices would be something like "0,1,2, 2, 3, 0".
The final vertex array and the submesh indices would look like this
// 0 1 2 3 4 5 6 7 8 9 10 11
Q0v0, Q0v1, Q0v2, Q0v3, Q1v0, Q1v1, Q1v2, Q1v3, Q2v0, Q2v1, Q2v2, Q2v3,
//| ------- Q0 --------- | --------- Q1 -------- | -------- Q2 -------- |
// indices
// submesh0 0, 1, 2, 2, 3, 0 // offset == 0
// submesh1 4, 5, 6, 6, 7, 4 // offset == 4
// submesh2 8, 9,10,10,11, 8 // offset == 8
Oh, I was not aware that several skinned mesh renderers would work with one skeleton, although i think i will do the offset version. Thanks for the help
Answer by paulorenan · Oct 03, 2018 at 08:15 AM
@mathias234
That might help you sort out part of the task, in case you still need it
public static List<int[]> OneVertexArrPerSubmesh(Mesh m, bool sort = false)
{
List<int[]> ret = null;
if (m.subMeshCount > 1)
{
ret = new List<int[]>();
for (int i = 0; i < m.subMeshCount; i++)
{
int[] submeshVerts = m.GetTriangles(i).Distinct().ToArray();
if(sort) Array.Sort(submeshVerts);
ret.Add(submeshVerts);
}
}
return ret;
}
I'm not sure what your code is supposed to do. Currently you don't even touch the vertices at all. You only mess with the triangle indices. Your use of Distinct as well as Array.Sort will completely destroy the actual triangles, so it's completely pointless. If you remove the Distinct and Sort all your code does is returning the seperate triangle array at once in a list.
I'm not sure you actually understood the problem here. If you have seperate vertex arrays that you want to merge you actually have several seperate meshes as input. He actually wants to create a single mesh with a single vertex array but several submeshes. However if you have seperate meshes the triangle indices in each mesh start at index 0. If you merge two (or more) meshes into one you have to merge the vertices first. Though the indices of the second mesh have to be shifted upwards to the end of the vertex array of the first one. So the indices of the first stay the same but the indices of the second mesh have to be shifted. That's what my pseudo code does in my comment above.
However you have to keep in $$anonymous$$d that a "vertex" also might have a normal, color, uv, ... associated with the position. So you have to merge all those arrays (if present) the same way.
Once you have merged the mesh that way you could use my $$anonymous$$eshWelder to remove duplicate vertices. This will again remap certain indices. Of course we can only merge vertices if they are actually exactly the same (same position, same normal, same uv, ...). That's what my $$anonymous$$eshWelder does.
The indices are nothing more than the indexes of vertices, refering to mesh.Vertices. So, by getting distinct indices, we get the vertices of each submesh. Sorry I didn't have the time to explain the idea. Possibility to Sort is something I thought that could be useful to optimise the data retrieving/access in some specific case that to be honest I can't think of right now.
// use shared$$anonymous$$esh if you call it from the editor (not playing), and mesh if you call from when it's playing.
$$anonymous$$esh m = gameObject.GetComponent<$$anonymous$$eshFilter>().shared$$anonymous$$esh;
List<int[]> sub$$anonymous$$eshesVertArrays = null;
if (m.sub$$anonymous$$eshCount > 1) // by default a mesh has one submesh
{
sub$$anonymous$$eshesVertArrays = OneVertexArrPerSubmesh(m);
}
for(int i = 0; i < sub$$anonymous$$eshesVertArrays.Count; i++){
// loop through submesh (i) vertices
for(int j = 0; j < sub$$anonymous$$eshesVertArrays[i].Length; j++){
Vector3 myVertex = m.vertices[sub$$anonymous$$eshesVertArrays[i][j]];
}
}
Problem is, if you have shared vertices, this will not work properly.