How can I control the sort order within a mesh I'm creating?

Hi,
I’m fairly new to creating meshes and quads. I’m trying to create a mesh in order to create a 2D tilemap where players can click to add and remove tiles. And it’s all based on a grid.
The idea is that the last tile added onto the tilemap should be drawn on top of the others (some tiles are overlapping each other).
With the unity tilemap, I wasn’t able to get the tiles to overlap each other properly. So I tried to create this mesh trying to follow CodeMonkey’s yoututbe tutorials.

But it seems like the quads are being rendered in order of the mesh index…with the highest index quad being drawn on top of the lower ones.
So I tried to add new tiles(quads) to the end of the mesh arrays(vertices, uvs and triangles) (while also removing the vertices, uvs and triangles and adjusting the index number corresponding to the old tile being replaced) and it’s working in terms of being able to draw on top of the other existing tiles(quads). But now, only the latest quad/tile I’m adding is being rendered on screen even though I can see the vertices, uv and triangle array all have the correct values in the correct order to draw the other quads on screen.
I have no idea why the other quads aren’t being rendered. All the mesh data that is being fed into the mesh seems to be correct. I’ve triple checked this using visual studio debugger.
I’m starting to think if this is a bug? Or something to do with the shader?
I’m starting to think i may not not be understanding something about meshes and shaders.
Any help will be appreciated. I’ve been scratching my head on this one for a week now.

This is basically the key parts of the code:

public void UpdateIndividualTile( Vector3 worldPosition)
{

grid.GetGridXY(worldPosition, out int x, out int y)
Vector3[ ] targetVertices;
Vector2[ ] targetUv
int[ ] targetTriangles;
int newIndex;
int existingQuadIndex = gridObject.quadIndex;

targetVertices = new Vector3[mesh.vertices.Length];
targetUv = new Vector2[mesh.uv.Length];
targetTriangles = new int[mesh.triangles.Length];
newIndex = targetVertices.Length / 4 - 1;

Vector3[ ] existingVertices = mesh.vertices;
Vector2[ ] existingUv = mesh.uv;
int[ ] existingTriangles = mesh.triangles;

Array.Copy(existingVertices, targetVertices, existingQuadIndex * 4);
Array.Copy(existingUv, targetUv, existingQuadIndex * 4);
Array.Copy(existingTriangles, targetTriangles, existingQuadIndex * 6);

Array.Copy(existingVertices, existingQuadIndex * 4 + 4, targetVertices, existingQuadIndex * 4, (existingVertices.Length - (existingQuadIndex * 4 + 4)));
Array.Copy(existingUv, existingQuadIndex * 4 + 4, targetUv, existingQuadIndex * 4, (existingUv.Length - (existingQuadIndex * 4 + 4)));
Array.Copy(existingTriangles, existingQuadIndex * 6 + 6, targetTriangles, existingQuadIndex * 6, (existingTriangles.Length - (existingQuadIndex * 6 + 6)));

for (int i = 0; i < grid.GetWidth(); i++)
{
for (int j = 0; j < grid.GetHeight(); j++)
{
if (grid.GetGridObject(i,j).quadIndex > existingQuadIndex)
{
grid.GetGridObject(i, j).quadIndex -= 1;
}
}
}

gridObject.quadIndex = newIndex;

int vIndex = newIndex* 4;
int vIndex0 = vIndex;
int vIndex1 = vIndex + 1;
int vIndex2 = vIndex + 2;
int vIndex3 = vIndex + 3;

baseSize *= (0.5f, 0.5f, 0);

vertices[vIndex0] = pos + new Vector3(-baseSize.x, baseSize.y);
vertices[vIndex1] = pos - baseSize;
vertices[vIndex2] = pos + new Vector3(baseSize.x, -baseSize.y);
vertices[vIndex3] = pos + baseSize;

int tIndex = index * 6;
triangles[tIndex+0] = vIndex0;
triangles[tIndex+1] = vIndex3;
triangles[tIndex+2] = vIndex1;
triangles[tIndex+3] = vIndex1;
triangles[tIndex+4] = vIndex3;
triangles[tIndex+5] = vIndex2;

mesh.Clear();
mesh.vertices = targetVertices;
mesh.uv = targetUv;
mesh.triangles = targetTriangles;

}

I don’t think there’s any guarantee of integrity or ordering of any Mesh data except in the case that you yourself keep track of all the vertices and the triangles.

If you want to control a mesh fully, maintaining the critical mapping from vertices to triangles, I think the only solution is to track it all yourself, change it in your own data, and when it changes, stream it all back to the Mesh object.

I remember early on trying to use mesh data ordering knowledge to accomplish some graphics trick and running into this issue, not to mention the separate reordering (and outright vertex dropping and duplicating) that happens (by design!) at mesh import time.

Thanks Kurt. I’ve added a bit more of my code to explain how I’m tracking the mesh data. I’m taking a copy of the mesh data locally and modifying it to include the new quads at a higher index. And when the code runs I can see the vertices, uvs and triangles are all perfectly ordered as it should be but it just won’t render on screen.
But when I run the code without trying to remove the old quad (as in when I add a new quad as just an extra quad to the mesh data with a new index, and comment out the Array.Copy part that removes the old quad data) it’s all rendering fine. So it’s only not rendering when I try to remove the old quad.
But in both cases, the mesh data i’m feeding in is correct. Can’t find any problems with it. The vertices and triangles all align.
I just can’t understand why removing the old quad data causes this issue. Aaarghhh!!

How did you track the mesh data when you solved your issue? Is there a better way of doing it?
Also, do you know of any other way to get individual tiles to draw on top of its neighbours within the same mesh?

This is where you should probably focus your effort: make an extremely small datasat, the smallest one you can make that still shows the problem, even if it is 2 or 3 quads and you remove one of them. Try removing the first, then the second, etc.

My money is riding on some kind of vert / triangle accounting bug. Source: I’ve written a few of these bugs myself. It’s complex to get it right. :slight_smile:

I’ve fabricated meshes from all sorts of data sources, such as the flat planes of a room defined by cells / pixels, or even the surrounding walls of a room defined by cells / pixels.

It’s always about breaking it down to a tiny 2x2 room and proving out your bookkeeping logic.

Yup you were right on the money. It was a problem with the triangles array. Even though I was removing the old quad’s triangles and adjusting the quad indexes of the remaining quads, I hadn’t adjusted the values for the remaining triangles. I just left them thinking they’re like the vertices and uv values. Finally got it working! It only took me a week! :eyes:
Thanks for the pointers!

1 Like

Don’t feel bad, it’s the way of programming.

I wrote a maze generating algorithm today and had bugs when I swear that thing was done right…

Turns out my usual lookup tables for X and Y going around the compass had a typo.

The correct initializer was:

int[] ytable4 = new int[] { +1, 0, -1, 0};

and I had reversed the +1 and -1 entries because I copied it from a utility that treated upper left corner as (0,0), whereas in this new project the (0,0) was at lower left.

It wasn’t until I whittled it down to 2x2 cell and found exactly what steps it was taking and why it looked wrong:

9482005--1333531--Screen Shot 2023-11-19 at 7.35.03 PM.png

(While I was working on the 2x2 level I zoomed the camera in super tight so the level filled the entire screen and I was like holding it by the necktie shaking it and asking it" WHY ARE YOU NOT PUTTING THE WALLS IN THE RIGHT SPOTS!?")

But yeah, that scared it… And now… all mo bettah!

9482005--1333534--Screenshot-KurtGame-133449249458092900.png