Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Making cg-modified versions of all shaders using SetReplacementShader

Discussion in 'Shaders' started by JeffersonTD, Jan 10, 2016.

  1. JeffersonTD

    JeffersonTD

    Joined:
    Feb 5, 2013
    Posts:
    267
    I would like to use SetReplacementShader to make modified versions of all shaders. They would be otherwise like the originals, except they would have a surface clipping function added to them.

    First a few principle questions related to this:
    1. It would of course be ideal if I could just append the clipping logic on top of any given shader programmatically. But I guess that is simply not possible?
    2. So assuming that I can't just automatically add logic to existing shaders, I need to separately add the clipping function to all shaders. And to make it work properly, I need to add the logic to all subshaders (as well as the fallback shaders) separately? Or is there a more simple way?
    3. Having a few different kinds of shaders replaced differently for the same camera should be possible to achieve using tags, right?

    Then for some more practical questions:
    • A. TAGS: I can't seem to get the tags working. If I don't pass a tag when calling the SetReplacementShader, it does render using the replacement shader, as expected. But if I do pass a tag for the function, it doesn't seem to render anything, no matter what I use as tags in the shader.
      • I find it also pretty confusing that you only need to pass a value, not the name of the tag. So does this mean that it doesn't matter what the tagname is as long as the value matches? That doesn't make much sense to me.
      • Tags can be defined on Subshader level and Pass level, but not on the level of the whole shader. Shouldn't I match the whole shader, not some part of it?
    • B. MATERIAL PROPERTIES: When I tried this with the Standard Shader it did apply the replacement, and even preserving the material properties as hoped - at first. However as I modified things and tried again, it started showing everything just plain black. I somehow got that fixed for a while and then it happened again. And now I found out that it appears to be so that it is only able to get the properties from the original shader if I temporarily change to the replacing shader manually for the object itself. And even then it only preserves the properties until some changes are done to the shader or Unity is restarted. So: is this a bug, or is keeping material properties (with same names) simply not supported?
     
    Last edited: Jan 12, 2016
  2. JeffersonTD

    JeffersonTD

    Joined:
    Feb 5, 2013
    Posts:
    267
    I have the impression that replacement shaders aren't that commonly used, but nevertheless, someone probably has some experience in successfully using them. Questions 1-3 aren't that relevant not, but any comments on the questions A and B about Tags and Material properties?
     
  3. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    I have successfully used them for pretty much the same reason, to add a clip plane. (And that was then intended for planar reflections.)

    In my case all the shaders are custom, which helps having full control over the tags. I have for example a shader A, which has a tag "Type"="A" in the subshader section. The replacement shader for A with clipping has the exact same tag. And then for each replacement you set the shader with:
    Code (csharp):
    1.  
    2. camera.SetReplacementShader(replacementShaderA, "Type");
    3.  
    For the rest:
    1. You could also make different passes and select the correct pass number. It is quite possible to add a clipping variant that reuses the original shader code. There is no way to do a generic replacement for this solution though:
    Code (csharp):
    1.  
    2. float4 frag(INPUT input) : COLOR {
    3.     return float4(1.0, 1.0, 0.0, 1.0);
    4. }
    5.  
    6. float4 frag_clip(INPUT input) : COLOR {
    7.     clip(input.a - 0.5);
    8.     return frag(input);
    9. }
    10.  
    2. Yes, and yes. You have to make replacements for all shaders and all their variants.
    3. Yes, you present the name of the tag to compare and it will replace if the value of that tag is the same as the original shader.

    A. You have to pass the name of the tag, not the value when replacing the shader. You'll have to define the tag in every subshader that needs replacement.
    B. I had no issues here and my replaced shader can have about 20 properties that are copied from the original shader.
     
    Last edited: Jan 13, 2016
    JeffersonTD likes this.
  4. JeffersonTD

    JeffersonTD

    Joined:
    Feb 5, 2013
    Posts:
    267
    Thanks for all the answers!

    I was able to make the tagging work, but for some reason the value that used for SetReplacementShader needed to be BOTH in the name and value of the tag in the shader. I tried it several times with all three combinations (having the name, having the value and having both) and only when both were there, it worked.

    The property problem still persists. The only way to make it work is swap temporarily to the shader that I want to replace to and then return to the original. As you're saying you've had no problems with it, I'm starting to think maybe it's a bug in Unity. Maybe I should try with another version of Unity. Maybe it could be even somehow related to Queue tag bug: http://forum.unity3d.com/threads/5-3p1-queue-tag-buggy.379544/ . I mean both are related to a need to swap shaders back and forth!
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,209
    As far as I know the queue tag is ignored when determining replacement shaders, the only thing it cares about is the type tag unless you override.