Using different UV for multiple model copies

I would appreciate to hear your opinion on how you would solve the following problem in the most efficient way, maybe someone here had some experience with something similar.

So the situation is like this: I have a classic jigsaw puzzle board made of many puzzle pieces. Each piece is a textured 3D model, if you put all of them together they form some 2D image. There is a fixed number of possible variations of pieces, so I can reuse the meshes for several pieces. The number of pieces may be very large, hopefully 1000-2000 if it is feasible.

I could do all this in 2D with sprites, but this is exactly the point - I want to try and make all the pieces real 3D models that look like they are made of cardboard, with some volume, reflections, maybe bump mapping if performance allows it.

One way to implement this is by assigning a separate material to each piece. All the materials will have the same texture, but different offset, so each piece shows a part of picture and together they form one big picture. Obviously this creates a performance problem, since as I said there could be many puzzle pieces, so we have really many materials.

Second way is to use UV mapping. Now all the pieces will have one shared material, but each piece will have a separate clone of mesh, each with different UV mapping. This way I am using only one material, but now it creates huge duplication of geometry - I cannot share the meshes between puzzle pieces, instead I have to hold a clone of a mesh for each piece with only one difference - UV mapping.

So what do you think would be the best solution for maximum performance? Maybe there is a third way that I don’t see? Maybe it is possible to duplicate just the UV mapping for each mesh, and not the whole mesh in some way that I don’t know?

The problem could be solved if I could pass somehow to the shader information of which piece it is currently rendering, but that seems to be possible only via either materials or geometry, same as I described above.

Please share your opinion, thank you.

You said

The number of pieces may be very large

In this case i wouldn’t recommend to use seperate meshes at all. As you said if you want different information on a per-piece basis you either need to have seperate pieces with each piece uses a different matieral (material instance) where you can adjust the settings for the shader (like the texture offset), or my encoding this information into the mesh itself.

Using seperate renderers has several disadvantages. First since you need different data for each piece you either need a seperate mesh for each piece, or you need a seperate material for each piece. The best option would be to use a SkinnedMeshRenderer, combine the mesh data of all pieces into one mesh and use “bones” to move each piece / part of the mesh seperately.

We don’t know how you piece-meshes look like and how exactly they fit together. A jigsaw puzzle usually is a rectangle. So your pieces usually have to fill that rectangle. If you have irregular pieces and you actually want to reuse certain pieces there has to be some kind of pattern in the piece design that allows this. It’s really difficult to give instructions for things we have no idea about how they look like.

Therefore it’s pointless to give a generic code example. Unity has a very simple example how to setup a skinnedmesh from code. Though you should be familiar with how a skinnedmesh works, what the boneweights and bindposes actually are and how to set them up. In essence you would fill a single mesh with the vertex / triangle data from your various pieces to fill the entire picture. During this process you give each vertex it’s corresponding uvs for their target position. Also all vertices belonging to a single piece get linked to exactly one bone index. The bones array of the skinned mesh renderer would need to contain as many bones as you have pices in your picture. They most likely are arranged in a grid pattern according to the piece positions. If everything is setup correctly you can move the empty bone gameobjects around and the piece geometry will follow.

Keep in mind that a usual childs jigsaw puzzle that has agrid of 10x10 pieces has already 100 pieces. Advanced puzzles have 1000 pieces or more. However we don’t know enough about your needs to go more into detail.

ok here goes. GPU instancing and UV map: encode all the tile UVs into a RG-Texture you assign to a material with custom shader which reads them instead of the meshes UVs (can be deleted there). since the puzzle is X*Y size you can arrange the color coded uvs into blocks into the texture. from the outside, you just pass in one. UV coordinate for each piece, which then reads the texture space with the pixels in there. this should work in combination with GPU instancing, since you pass single data instead of an UV array.