Texture Mapping on a Tile Map - How to Treat Joint Vertices and Odd Stretching Artifacts

Hello, all.

I am new to Unity, 3D, and these forums, so please forgive me if the solutions to the troubles I’m experiencing are terribly obvious. I searched the forums and Google for some insight into the issues I’m experiencing, but to no avail.

I’m working on a procedurally generated tile map as a beginning step toward a game I have in mind. I used the following tutorials/guides as starting references (Catlike Coding - Unity C# Tutorials: Procedural Grid and Quill18Creates - Unity 3D Tutorial: Tile Maps (Civilization, Dungeon Crawler)). They’re great and have helped a lot in my basic understanding. However, they do not help to provide insight into what I’m experiencing.

First, when trying to apply one tile from my sprite sheet to one quad in my mesh via UV texture mapping, there is a strange artifact, a sort of stretching behavior, of parts of the sprite sheet across the other quads. Is there a setting I am overlooking to prevent this behavior? From my limited past 2D experience using HTML5 Canvas and/or Phaser, I was expecting this to be as simple as blitting from my texture to the mesh, but that doesn’t seem to be the way to approach 2D Tile Maps, based on what I can find. Following are my tile sheet and the result of mapping the last sprite in the sheet to the first quad (bottom left of mesh).

3193862--243959--tilesheet.PNG

3193862--243960--single.PNG

The other problem I’m having is in understanding how I accomplish these mappings when quads share vertices but map to different points in the texture. For example, in the following image, the center point is a shared vertex for all four quads. When I map the sprite to the upper right quad, it naturally changes what the top right vertex of the bottom left quad is mapped to, resulting in something that looks like this:

3193862--243961--sharedVertex.PNG

Thank you in advance for any direction or help you can provide. I greatly appreciate it!

First, welcome to the Unity community! It’s a great place to be and I’m excited that you’re here. But, what you’re attempting to do (and indeed, what you’ve done already) is not really beginner-level Unity stuff. It’s pretty advanced.

You might want to search the Asset store for any of the several good tile map engines you will find there. These have already done the deep magic, and probably done a very good job of it (check the reviews to be sure).

If you want to do it yourself, the simplest method would be to just use a bunch of Sprite objects, one for each tile. You can create and arrange these in code so you don’t have to painstakingly arrange them by hand. Your source image is probably a single image with a little square area for each type of map cell you support; just set the import type to “Sprite - Multiple” and then you can easily carve these up into individual sprites (by rows/columns or by tile size). Then just assign the correct sprite to each object in the scene to create your map.

If you still want to do it through procedural mesh generation, then what you need to do is create a separate 2 triangles (from a separate 4 vertices) for each tile in the map. That is the only way you can assign a different UV coordinate to a point for each of the four neighboring cells, thus avoiding the problems you discovered.

Of course once you’ve done that, you’ve essentially just re-created the sprite engine. Unity already batches sprites into one big mesh under the hood when it can (for example, when they’re all using sprites from the same atlas, as would be the case here). So there probably isn’t much benefit to going to all that work yourself, except of course the value of learning how.

Good luck, and keep us posted!

Thank you for the response, JoeStrout. I should probably provide a little more background to my explanation in order to give a slightly better idea as to what I’m attempting to do.

My map could be very large, so I wanted to avoid creating an object for every tile. Further, the map will be dynamic. As a player moves from one square to another, the texture of that tile will change to some other texture, which is unique to the player that steps onto it.

I do currently have two triangles for each quad. Each quad has four vertices, we’ll say [0, 1, 2, 3]. Assuming their vertices are defined as:

23
01

Then the first and second triangles would have Vector3 values of [0, 2, 1] and [1, 2, 3], respectively.

It is my understanding that a UV value is assigned to each unique vertex. Is this incorrect? Is it instead tied to each vertex of each triangle? In other words, in my example above, I’d have 6 UV mapping values and not just 4.

I hope that makes sense and helps to clarify what I’m trying to accomplish. If individual objects are the only reasonable solution, I could pursue that option. However, it seems rather cumbersome based on my limited experience.

Another way to consider this, I suppose, is if I was instead working on a 3D project and I wanted to create a simple farm where the type of plant I am growing (texture shown on the ground) would change from row to row. I would imagine this is possible with a single mesh, perhaps even with varying elevations if I was trying to convey a small slope (using z value in this case, where it’s normally 0 for my 2D tile map). Wouldn’t I be able to map those different plant type textures from a single sprite sheet to the mesh, even though the rows would share vertices?

At any rate, below is an example mocked up in Tiled of what I would expect to be able to do. Perhaps a mesh is not the appropriate approach.

You can certainly do it with a mesh. It’s just that you will have to stop sharing vertices between tiles.

Yes, but I don’t believe each quad has its own four vertices. I think you’re sharing them between tiles, and that won’t work in this case.

No, that’s exactly right. So, two neighboring tiles can’t share corner vertices, since they need unique UV values.

It’s not cumbersome, but there certainly is overhead in having lots of GameObjects. So the mesh will perform better if you can pull it off. However, you might be surprised at how efficient Unity can be, assuming all those GameObjects don’t have any MonoBehaviours on them — the difference in performance might not be noticeable.

This is exactly what I suspected! So I revised my script and we’re now working as I’d originally hoped for. Thank you. Further, this new approach removes pitfalls I suspected would arise in future steps, where I was going to have to do some undesirable logic to handle these shared vertices and such.

3194231--243979--working.PNG

If I created a script and assigned it to a GameObject, which I then made a PreFab so that I could easily duplicate it for each tile, wouldn’t each tile have MonoBehaviours, since each is tied to the script that’s derived from the MonoBehaviour parent class? Among other things, I intend to write a script that handles raycasting to determine the tile the mouse is over, allow certain behaviors based on the state of that tile (e.g. occupied, free, contested, etc.), in a turn based fashion.

This is all still early and new to me, so forgive my ignorance if my assumptions are poor.

Thanks again, Joe!

Your assumptions are correct, but since you’re going with the procedural mesh route, I don’t think you have a problem. One object will be either your entire map, or at least a good-sized chunk of it, right? So you’ll be looking at a small number of GameObjects for it in the scene. No problem at all.

Good work getting that ironed out! You’re definitely not taking the common/easy path to Unity mastery, but you’re getting there rapidly nonetheless!

Yes, that’s incorrect.

Yes, all vertex attributes are per-vertex. A tile map would require a separate quad (6 triangle indices) for every tile, and none of the indices can be shared with neighboring tiles if you want to UV map them correctly.

If you have each tile be a GameObject, there’s no reason to have scripts on the tile GameObjects. (And lots of reasons not to.)

Also no reason to use raycasting (I assume you mean that), and again lots of reasons not to. Just convert screen coords to whatever corresponds to the tile. The general idea for tilemaps is that you have an internal array with the desired info that represents the world; whether it’s displayed with sprites, meshes, etc. is just a display detail and wouldn’t affect mouseover stuff.

–Eric

Thanks, guys, for the helpful input.

Eric, if I understand what you’re saying in your later remarks:

  • Whether I use Sprite objects or a single Mesh object is mostly irrelevant, so long as I am careful about what I assign scripts to and if necessary. The large scale data about my map should be stored behind-the-scenes in an array but not displayed on-screen all at once. This is what I am accustomed to.

Based on Joe’s and your feedback, I think I’m going to revise my approach once more to use Sprites instead of a mesh. Further I’m going to modify the scope of my map to only create as many sprite objects as are needed to fill the screen and update the texture applied to each based on where the “camera” is positioned in regards to the behind-the-scenes map array.

1 Like