Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Nested materials

Discussion in 'General Graphics' started by exltus, Mar 24, 2021.

  1. exltus

    exltus

    Joined:
    Oct 10, 2015
    Posts:
    58
    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?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    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.
    https://docs.unity3d.com/ScriptReference/MaterialPropertyBlock.html
    https://docs.unity3d.com/ScriptReference/Renderer.SetPropertyBlock.html

    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.
     
  3. exltus

    exltus

    Joined:
    Oct 10, 2015
    Posts:
    58
    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 :(
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    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.