Nested materials

Hi, Iam wondering how to achive nested materials - I mean how to create root material and its overrided form. Same like new nested prefabs works.

Lets imagine this simple case:

  • I have material for FPV weapon which uses material with simple shader with base color texture and tint color
  • Next I have TPV weapon which uses exactly same texture but different tint color

Iam looking for solution how to create override material for my TPV weapon wchich will be based on my FPV material (so it will inherit texture and tint collor settings), but I will only manually override its tint color and keep texture unchanged - this will mean that when if I change texture on FPV weapon it will also change on my TPV material, but when I will change my tint color it will be not changed on my TPV materil. This is exact workflow like current nested prefabs implementation.

Is it possible to achieve it with materials? Or I have to handle those changes manually?

There’s no way to do this with Unity’s material system as is. Unreal’s concept of material instances is something I really do miss from that engine. The request for this has come up a few times, and I think it was even on some official public list of features under consideration at some point, but it doesn’t seem to be there anymore.

However, there still is a way to do this, at least when paired with prefabs. The trick is to use a custom script that overrides material properties using a MaterialPropertyBlock. Unity’s upcoming Hybrid Renderer (for rendering ECS components in either the URP or HDRP) even appears to have code for this exact kind of setup, though the code for that isn’t directly usable without the Hybrid Renderer.

The idea with the MaterialPropertyBlock is you assign override values for a material on the MaterialPropertyBlock, and set that on renderer component.

You’d want to make a component script with a list of property names and types, and on start (or on Update while in edit mode) have it create a MaterialPropertyBlock, assign the the properties, and set it on the renderer component. It’s not quite nested materials, but if you already have prefab variants you could add or override the scripts properties which would give you similar control.

Thanks for your answer. It was really helpful. I already implemented solution that you mentioned, but I found another problem. What if I need to change shader? I have 2 totally same shaders but one uses outline pass and one does not :frowning:

If you need a different shader, then you need a different material. There’s no way around that limitation.

However if the two shaders are otherwise similar enough, a trick I use to avoid creating a ton of additional materials is to copy all of the relevant material information from the original material to a material property block, and then I use a common shared “effect” material that I assign to the renderer.

The other option is to separate out the outline pass and render it as a separate material or even using command buffers instead of a multi-pass shader.