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

Modifying the shader properties of only one object?

Discussion in 'UGUI & TextMesh Pro' started by Democide, Jan 8, 2016.

  1. Democide

    Democide

    Joined:
    Jan 29, 2013
    Posts:
    315
    So I'm playing around with shaders and it seems to be impossible to modify the shader properties of on UI object only. The CanvasRenderer only has a GetMaterial method, no material field. So I always get the reference to the shared material, not the actual instance, which makes all changes propagate to all other objects.

    Anyone have a solution for this?
     
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,227
    You want to change the material properties for one UI item?
    Can you not just assign a different material to it?
     
  3. Democide

    Democide

    Joined:
    Jan 29, 2013
    Posts:
    315
    Well, no. Say i have a glitch shader, that I can toggle, and I want specific items to glitch at runtime. I COULD make a bunch of duplicates of that material and then work that way, but that seems... ridiculous.
     
    mdashholdings2 and awsapps like this.
  4. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,227
  5. Stephan-B

    Stephan-B

    Joined:
    Feb 23, 2011
    Posts:
    2,269
    fffMalzbier likes this.
  6. VamossVoar

    VamossVoar

    Joined:
    Oct 24, 2014
    Posts:
    4
  7. VamossVoar

    VamossVoar

    Joined:
    Oct 24, 2014
    Posts:
    4
    Found the solution!
    To remove the shared material you will need to instante the material(create a new one) and then set back to the image:
    Material mat = Instantiate(image.material);
    image.material = mat;
     
    Kevin_OBrien and VladaVlajic like this.
  8. wihu

    wihu

    Joined:
    Nov 22, 2012
    Posts:
    25
    it would be nice if we dont need to duplicate material for each item.
    is this still being worked on by Unity team?
     
    swingingtom, awsapps and teemukorh like this.
  9. teemukorh

    teemukorh

    Joined:
    Oct 28, 2014
    Posts:
    49
    I guess this is still not supported?
     
  10. ElChileVengador

    ElChileVengador

    Joined:
    Feb 4, 2013
    Posts:
    27
    I just want to bumb the idea of MaterialPropertyBlocks for CanvasRenderers
     
  11. treecki

    treecki

    Joined:
    Feb 6, 2017
    Posts:
    29
    5year.jpg

    Bumping in 2021. Would really like to not create a new material eachtime...
     
    awsapps and Keitaro_Ura like this.
  12. bion

    bion

    Joined:
    Oct 25, 2012
    Posts:
    11
    also waiting!!!
     
  13. GunnarHerbert

    GunnarHerbert

    Joined:
    Nov 17, 2020
    Posts:
    1
    yeah, i need to find a similar solution
     
  14. EntropyRequiem

    EntropyRequiem

    Joined:
    Aug 11, 2021
    Posts:
    1
    Holy S***, still no solution? Come on Unity..
     
    Keitaro_Ura likes this.
  15. Divinum-Fulmen

    Divinum-Fulmen

    Joined:
    Jul 11, 2014
    Posts:
    8
    I came up with this cool idea: What if instead of rotating a sprite's mesh, I just rotate the shader's UVs! But then I ran into a problem. Rotating one shader does it to every image using it. Searching for a solution brought me here, a dead end.
     
  16. Indie_Core

    Indie_Core

    Joined:
    Jun 14, 2021
    Posts:
    6
    Really? There should be a checkbox in object's shader material where it says "original/distinct" and you operate on completely original material how come there's no solution to that in any other way than creating it runtime?
     
  17. panda2333

    panda2333

    Joined:
    May 3, 2022
    Posts:
    1
    aahhhhhh
     
  18. Smellfish

    Smellfish

    Joined:
    Feb 21, 2020
    Posts:
    8
    It would be nice to see this become a thing. I don't like having a million materials when one or two can suffice.
     
  19. HassaanMustafa

    HassaanMustafa

    Joined:
    Feb 17, 2019
    Posts:
    2
    HERE'S THE SOLUTION!!!

    GetComponent<MeshRenderer>().material
    GetComponent<MeshRenderer>().sharedMaterial

    NOTE: The first line sets the variable of a material/shader of ONLY ONE object while the second line changes the variable of material/shader of all the objects having that material/shader.
    Thank me later :)
     
    Last edited: Oct 3, 2022
  20. h-dragon919

    h-dragon919

    Joined:
    Jul 29, 2020
    Posts:
    19
    Thanks a lot Hassan(btw my name's Hassan too!, the h in h-dragon stands for it)
     
    d2clon likes this.
  21. jacksonkr

    jacksonkr

    Joined:
    Jan 22, 2013
    Posts:
    22
    is there any way to do this directly through the inspector? asking for a friend..
     
    Nit_Ram likes this.
  22. aabee

    aabee

    Joined:
    Jun 4, 2016
    Posts:
    2
    EDIT: Apparently CanvasRenderer does not support this. :(
    EDIT2: Apparently Unity decided to remove the [PerRendererData] functionality and make it work just like HideInInspector. You can, however, do this: https://twitter.com/minionsart/status/1069973103604846593?s=19


    If your objects have the same mesh, use GPU Instancing, it is faster.

    If your objects have different meshes, you need to use PerRendererData. It is faster than having separate materials for each of these objects, but slower than GPU instancing.

    This can be achieved by adding [PerRendererData] in the shader in front of the properties that you want to be different for each object using it:

    Code (CSharp):
    1. Shader "Custom/StandardSpecularClippable"
    2. {
    3.     Properties
    4.     {
    5.         [PerRendererData]_MainColor("Color", Color) = (1,1,1,1)
    6.         _MainTex("Albedo", 2D) = "white" {}
    7.  
    8.         _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
    9.  
    10.         ...
    11.     }
    12.  
    13.     ...
    14.  
    15. }
    For ShaderGraph Shaders, you have to select the .shadergraph file in the editor, select "view generated shader" and save that as a shaderfile, then add it to a material and use it instead of the shadergraph version.

    Doing this hides these values from the inspector (do not ask me why) and forces you to change the color through code like this:
    Disclaimer: All code has been written here by hand and may contain typos and errors, but the basic idea is correct.

    Code (CSharp):
    1. MaterialPropertyBlock mpb = new MaterialPropertyBlock();
    2. mpb.SetColor("_MainColor", Color.red); // Use whatever color you want.
    3.  
    4. Renderer rend = myobject.GetComponent<Renderer>();
    5. rend.SetPropertyBlock(mpb);
    6.  
    Do not use this for properties that do not have the [PerRendererData], that will cause new material instances to be made and you lose the performance benefits.

    You can also poll for the values that are [PerRendererData] like this:

    Code (CSharp):
    1. MaterialPropertyBlock mpb = new MaterialPropertyBlock();
    2. Renderer rend = myobject.GetComponent<Renderer>();
    3. rend.GetPropertyBlock(mpb);
    4. Color col = mpb.GetColor("_MainColor");
    If there is no [PerRendererData] on what you want to poll for, you will not find it in the fetched materialpropertyblock. You have to use renderer.sharedMaterial.GetColor(...) for example.
     
    Last edited: Oct 6, 2023