Drawing skinned mesh instances with different colors

Hello, I’m working on a prototype with custom RP, and I’m thinking about how to manage color variants of items. What’s the best(efficient) way to do this? Lets assume I have a piece of clothing and I want characters to have different color of it. Seems like I have to either

  • instantiate material and set custom color as cbuffer property, then directly apply in shader
  • instantiate mesh and bake custom color into vertex channels to get from vertex data in shader
  • provide additional vertex streams for each renderer: seem not to work with SRP batcher

Ofcourse, copying materials looks better than copying meshes, but may be there’s even better way? Hope for your advice.

The way I do it is I have a single material that has a texture palette with the colours I need, and apply texture offsets at runtime to shift the colours. That’s very efficient because it keeps the number of materials as low as possible (1). However, this works for me because I’m using a low-poly style with few colours, so your mileage may vary.

1 Like

Yeah, but how do you pass these offsets into shader? Please explain how can you keep 1 material and have it render with customized offset per object. I can’t use PropertyBlocks, because I’m dealing with skinned meshes.

I don’t. The shader does not need to know explicitly. If I’d change the material assigned that would be a different problem, but I don’t have to, I just do the following in script:

GetComponent().material.mainTextureOffset=new Vector2(xOffset,yOffset);

This works on a per-model basis, so changing one instance doesn’t change all of them. They still use the same material, allowing GPU instancing and all that.

EDIT: To clarify further, my skinned meshes have some colours that I’d like to remain constant and some that I do not, and I deal with this by offsetting the texture coords such that the colours I want unchanged are still within the texture region of the same colour while those that I do want changed shift out. I achieve this in two ways: when assigning UV coords to the model in e.g. Blender, I put the colours that should be variable close to the “edge” of their colour region, so that a small offset will shift them to a new colour; second, the colours you want unchanged can have larger regions in the texture (more area).

Then you should have as many materials as models, because accessing Renderer.material automatically instantiates it:
https://docs.unity3d.com/ScriptReference/Renderer-material.html

Aslo, GPU instancing doesn’t support skinned meshes.

Thanks for sharing. Yeah, it can be done in different ways, uv shifting or alpha-mask or something else.