- Home /
Optimization for lots of UV coordinates update for tilemap animation
In my game, I procedurally generate tile map mesh and modify it when travelling around the "world". Each tile is a quad. So they each, have their own UV points. (Obviously)
I am using Unity for this, and in Unity, i can't have more then 65k vertices in a single mesh.
So i made this "tile mesh", chunk based. It's still a single mesh. But while I am creating it, i first create the "chunks", (which are 16x16 quad meshes), then i "merge" the chunk meshes to create the tile map mesh.
I keep these "chunk meshes" in a list. So basicly i merge all the meshes in the list when i want to "update" the tilemap mesh.
While i am travelling in the world, i can remove farthest chunk from list, and add new chunkes when it's necessary. List capacity is fixed to 9, so i can never exceed the "65k vertices limit".
Now the problem is, when i zoom out in game, there becomes almost 40k vertices in the scene since whole mesh becomes rendered. (Actually since it's a single mesh, it always renedered as whole, but the animation doesn't occur out side of the camera view)
But when i zoom out, there are like atleast (6x6)x(16x16) = 9.216 tiles. Which makes 36.864 vertices (and UV points).
Now updating few tiles (so few uv points) is easy. But updating the whole 36k point takes like 1-2 seconds. Which is really bad for updating animation in that way.
The code snippet for single quad uv update is here
public void SetTile(Coord chunkCoord, Coord tileCoord, Sprite sprite)
{
Vector2[] uv = meshFilter.mesh.uv;
Rect spriteRect = sprite.textureRect;
int chunkIndex = SearchForChunk(chunkCoord);
if (chunkIndex == -1)
{
Debug.LogError("Chunk not found");
return;
}
int ui = chunkIndex * (16 * 16) + (tileCoord.Y * 16 + tileCoord.X);
ui *= 4;
uv[ui] = ToUV(new Vector2(spriteRect.xMin, spriteRect.yMax), sprite.texture);
uv[ui + 1] = ToUV(new Vector2(spriteRect.xMin, spriteRect.yMin), sprite.texture);
uv[ui + 2] = ToUV(new Vector2(spriteRect.xMax, spriteRect.yMin), sprite.texture);
uv[ui + 3] = ToUV(new Vector2(spriteRect.xMax, spriteRect.yMax), sprite.texture);
meshFilter.mesh.uv = uv;
}
It takes chunk coordinate, and finds that chunk in the chunk list, so i can get the index of that chunk mesh for UV array.
The sprite that i get as a parameter is in a "sprite atlas", so i call a helper function to convert it's rectangle to uv points.
That's how i update a single tile's UV points.
But It's too slow, how can i optimize it, make it faster?
Any reason why you have to have one single mesh from the combines chunks? Games like $$anonymous$$inecraft typycally just have multiple meshes, one per chunk, and create/destroy them based on the player position. This will net you more gameobjects, but smaller meshese, and you only have to create a few at a time ins$$anonymous$$d of all of them.
That would also work, i could have chunk gameobjects in game, but at that point, i don't think it would make any difference on the problem.
Btw, i kinda speed it up, by not updating mesh uv, but updating a seperate uv array, and assign it to the mesh.uv after for X seconds (animation time).
That way, i am not updating the mesh.uv each time i set a single tile uv. I am setting them in a seperate array, and assign the whole array to mesh.uv.
That tremendously increased the process speed. But i believe it's still somehow slow. But i'm still not sure.
It takes 0.03 to 0.05 seconds for each uv update call.