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

Question How could we add multiple shaders/materials to a single Sprite at runtime?

Discussion in 'General Graphics' started by tzxbbo, Jun 5, 2023.

  1. tzxbbo

    tzxbbo

    Joined:
    Dec 14, 2019
    Posts:
    94
    Hi, I'm not very firmilar with shaders, basically I wish to add effects to my 2d characters at runtime, spawning sub effect object isn't always the best option, but it looks like we can only assign one material to a sprite at a time, which means we can swap different effects but not adding them.

    What I want to achieve is basically adding effects on top of each other just like how we do postprocessing but not to the whole screen, which requires a combination of shaders/materials, I know we could combine materials in the editor, but I need this functionality at runtime.

    I see people using shadergraph expose fields so they could edit them in the inspector, I'm wondering if we could expose a field that basically represents a material/shader so that we could chain materials to each other and adding their effects on top.

    If this isn't the case then how could we properly do it?
     
  2. tzxbbo

    tzxbbo

    Joined:
    Dec 14, 2019
    Posts:
    94
    Anyone?
     
  3. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,554
    Here's what you CAN do.

    You can make a shader that includes multiple variants which you toggle using shader variants. Normally this would be done in birp, and I'm not sure if variants are easily accessible through shader graph. Probably should be.

    Another thing you can do is using dynamic flow control. Shaders support if/else and loops and also arrays. So you could develop arrays of parameters, tell the shader how many of them are used and render material stack using a loop. Technically there will be a limit on upper number of limitations, and f or textures you'd need to use texturearrays or atlases. Again, AFAIK this will require hlsl.
     
  4. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,617
    This is specifically the kind of thing that the "Keyword" parameters are for in a ShaderGraph. In this case you'd want to use "Multi-compile" type keywords. This tells Unity to compile variants of the shader for each combination of those keywords, and when the material is used it selects from the compiled variants based on which keywords are toggled.

    I've not tried specifically, but I suggest checking out whether you can use a keyword to include / exclude a sub-graph.If you can, then you can implement each effect as a sub-graph, and enable / disable them via the keyword properties on the material.

    One thing to note is that the number of shader variants increases exponentially based on the number of keywords. 1 keyword = 2 variants (on / off), 2 keywords = 4 variants (on|on / on|off / off|on / off|off), etc. This can impact build time, and maybe memory usage if you go nuts.

    Another thing to note is that while it's technically "less efficient", simply using a control variable (i.e. a float parameter) and a branch might achieve the same thing with negligible performance impact and a much lower shader variant count. From what I've read, on modern GPUs the cost of branching is very low in typical use cases, so depending on your target platform and the complexity of whatever else is going on that might be a perfectly reasonable approach. So, what is "modern" and "typical"? Well, it varies, so you'll have to test on your target devices to see what's the best way forward.
     
  5. tzxbbo

    tzxbbo

    Joined:
    Dec 14, 2019
    Posts:
    94
    Unfortunately, this won't work for me, I may have hundreds of effects in my game so I really need them to be freely combined, but not toggling on and off. Is it possible to output the final texture of a shader graph?
     
  6. tzxbbo

    tzxbbo

    Joined:
    Dec 14, 2019
    Posts:
    94
    I did a bit of research into sprite, it seems Sprite does support multiple materials? it's just in the inspector it's only allowed to assign one material, but we can assign more through codes... I'm not sure whether this is legal
     
  7. stain2319

    stain2319

    Joined:
    Mar 2, 2020
    Posts:
    417
    Is a player going to be able to discern a sprite with dozens or hundreds of effects applied simultaneously? At some point it seems like this will be very "busy" or "noisy" and once you get past 5 or 6 it will be very difficult to tell one combination of effects from another.
     
    angrypenguin likes this.
  8. tzxbbo

    tzxbbo

    Joined:
    Dec 14, 2019
    Posts:
    94
    Not simultaneously, but there will be a lot effects in total. The problem is with other mesh renderer it seems you can achieve this by simply adding materials to the mat array, but SpriteRenderer somehow only support a single material at a time, not sure why
     
  9. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,616
    Why can't you just use more than one sprite?
     
  10. tzxbbo

    tzxbbo

    Joined:
    Dec 14, 2019
    Posts:
    94
    Do you mean having multiple SpriteRenders with the same Sprite, basically having a stack of the same sprite. I had this idea before but it's not perfect either. If you apply some shader that skew the shape of the front sprite, those sprites behind would expose themself since they are not affected. It would be best if we could combine materials/shaders at runtime, I just don't know if such a thing exists. I heared that there's a way to do it using the built-in render pipeline, but not in URP, sadly
     
  11. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,617
    Or a custom script which submits additional draw requests.