- Home /
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.
I have a suggestion I don't know will work and how exactly:
you extract the UV data from the map into lets say a Vector2 array with identical layout for each puzzle piece.
the shader, rendering your pieces uses that data, unique to each piece as input...
maybe that's something
another hint might be laying on this page:
https://www.google.de/amp/s/matthewragan.com/2015/08/26/advanced-instancing-puzzle-pieces-touchdesigner/amp/
Thanks for the response, but that's exactly the problem, how do you do something like that in Unity? The problem is that when the shader is running - it has no idea which puzzle piece is it rendering. If I could make the shader know what piece is it rendering right now, I could easily solve all my problems with a custom shader, but the only ways I know how to pass such info to the shader is either by material or by mesh, exactly the two cases I described above. Well there are also uniform variables, but I don't see how this helps. Thank you.
Answer by hexagonius · Oct 22, 2018 at 04:55 PM
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.
Thank you, GPU instancing is the functionality I was looking for. What I do now - I pass texture offset as per-instance property to the shader and it does the job, like charm. Encoding UVs in a texture is a beautiful and elegant idea, but my case is much simpler so it is uneccessary. Thank you, this solves my problem.
Answer by Bunny83 · Oct 21, 2018 at 09:29 AM
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.
Thank you, you gave me a very interesting idea, I didn't even think about using Skinned$$anonymous$$eshRenderer before, so I will try it out. Basically, what I am trying to do (I will also update the question) is a classic 2D jigsaw puzzle, but using 3D and not 2D sprite graphics like most similar games, i.e. each piece looks like an actual puzzle piece made of cardboard, with some volume and reflections, you can view it from different angles etc. There is a fixed pool of possible shapes of puzzle pieces, so I can reuse geometry, and I also want to.
The problem I see with using Skinned$$anonymous$$eshRenderer is that I still cannot reuse geometry, and I cannot use dynamic LOD (which I suspect will be essential with large puzzles), but I will give it a try and do some benchmarks.
Thanks for your response.
Your answer
Follow this Question
Related Questions
Bast way to combine multiple materials into one 0 Answers
is it possible adding text in realtime using shadergraph? 0 Answers
How do I properly apply a transparent texture to a mesh? 2 Answers
Is it possible to use Multiple Materials on a single mesh? 0 Answers
How do you dynamically tile sub-portions of a plane? 1 Answer