Search Unity

Configurable Shaders (Open Source Project)

Discussion in 'Shaders' started by Johannski, Feb 23, 2018.

  1. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    826


    Configurable Shaders
    Github | Wiki

    Don't repeat yourself by writing the same shaders over and over again with little variation. You can expose a lot of different shader settings through attributes! Configurable Shaders does three main things:
    1. Provide unlit and lit Shaders for Opaque, Cutout and Transparent RenderTypes with a lot of configuration.
    2. Provide new useful Material Property Drawers and Debug Shaders
    3. Document the hidden features of shaders, that are not that apparent from the Unity Docs.
    Configurable Shaders is an Open Source community project to make usage of shaders easier. The project is meant for the built in Render Pipeline and exposes some awesome properties and gives you asuite of useful base shaders.

    Original Post
    Just wanted to share a simple yet very useful materialpropertydrawer: Enum
    Enums can be used like this:
    Code (CSharp):
    1. [Enum(Off,0,Front,1,Back,2)] _Culling ("Culling", Int) = 2
    This is super powerful, because you can make your life a lot easier if you want to expose properties for for culling or stencil operations you can connect the value to the actual meaning.
    I made a simple stencil shader, that supports all necessary settings for stencil operations.


    Shaderfile with documentation here: https://github.com/supyrb/ConfigurableShaders/wiki/Stencil

    Hope this helps somebody since I had quite a hard time getting stencil operations right without the knowledge that I can just expose those values in the material.

    Cheers
    Johannes

    Edit: Moved file to repository to document more enum types and possibilites
     

    Attached Files:

    Last edited: Apr 1, 2020
    FM-Productions, ModLunar and RG_Keith like this.
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    You can also use the existing script enums to simply this:

    [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp ("Stencil Comparison", Float) = 6
    [Enum(UnityEngine.Rendering.StencilOp)] _StencilOp ("Stencil Operation", Float) = 0
    [Enum(UnityEngine.Rendering.StencilOp)] _StencilFail ("Stencil Fail", Float) = 0
    [Enum(UnityEngine.Rendering.StencilOp)] _StencilZFail ("Stencil ZFail", Float) = 0
     
  3. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    826
    Holy crap! This is way more beautiful, I needed to dig throguh the decompiled version to find out which number represents what. This is way cooler! Is this documented somewhere. Also @bgolus can you tell me if using culling as a property creates different shader variants internally? Is there any drawback to expose those paramteres in the properties? :)
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Same as what you had before. They're the same enums Unity uses internally to figure out what each number means, though the order in the documentation doesn't match the actual enum in my experience.

    https://docs.unity3d.com/ScriptReference/MaterialPropertyDrawer.html

    No. Variants are only for code changes inside the CGPROGRAM blocks. Like any other material property it does prevent batching between materials what that value changed and cannot be modified per instance.
     
  5. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    826
    I got a bit carried away, and thought since there are quite a lot of possibilites that I haven't seen being used, I should document them so others can get that information more easily. I made a small repo with documenting stencil operations, as well as Cull, ZTest, ZWrite and ColorMaskWrite. Link to the new repo: https://github.com/supyrb/ConfigurableShaders

    However, if've noticed a strange problem with the stencil shader. Somehow the ZWrite property is ignored for the shadow pass (If've included my own shadowcasterpass which uses the same ZWrite property). When setting ZWrite in code, it works as expected and for non-stencil shaders it seems to work as well.
    In the frame debugger you can see, that the Zwrite is set to on, even though it should be off.
    upload_2018-2-25_22-51-58.png



    For reference, this is the shadercode:
    Code (CSharp):
    1.  
    2. Shader "ConfigurableShaders/Stencil"
    3. {
    4.     Properties
    5.     {      
    6.         [HDR] _Color("Color", Color) = (1,1,1,1)
    7.        
    8.         [Header(Stencil)]
    9.         _Stencil ("Stencil ID [0;255]", Float) = 0
    10.         _ReadMask ("ReadMask [0;255]", Int) = 255
    11.         _WriteMask ("WriteMask [0;255]", Int) = 255
    12.         [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp ("Stencil Comparison", Int) = 3
    13.         [Enum(UnityEngine.Rendering.StencilOp)] _StencilOp ("Stencil Operation", Int) = 0
    14.         [Enum(UnityEngine.Rendering.StencilOp)] _StencilFail ("Stencil Fail", Int) = 0
    15.         [Enum(UnityEngine.Rendering.StencilOp)] _StencilZFail ("Stencil ZFail", Int) = 0
    16.        
    17.         [Header(Rendering)]
    18.         [Enum(UnityEngine.Rendering.CullMode)] _Culling ("Culling", Int) = 2
    19.         [Enum(Off,0,On,1)] _ZWrite("ZWrite", Int) = 1
    20.         [Enum(None,0,Alpha,1,Red,8,Green,4,Blue,2,RGB,14,RGBA,15)] _ColorMask("Writing Color Mask", Int) = 15
    21.     }
    22.    
    23.     CGINCLUDE
    24.     #include "UnityCG.cginc"
    25.    
    26.     fixed4 _Color;
    27.    
    28.     struct v2f
    29.     {
    30.         float4 vertex : SV_POSITION;
    31.     };
    32.    
    33.     v2f vert (float4 vertex : POSITION)
    34.     {
    35.         v2f o;
    36.         o.vertex = UnityObjectToClipPos(vertex);
    37.         return o;
    38.     }
    39.    
    40.     fixed4 frag (v2f i) : SV_Target
    41.     {
    42.         return _Color;
    43.     }
    44.    
    45.     struct v2fShaodw {
    46.         V2F_SHADOW_CASTER;
    47.         UNITY_VERTEX_OUTPUT_STEREO
    48.     };
    49.  
    50.     v2fShaodw vertShadow( appdata_base v )
    51.     {
    52.         v2fShaodw o;
    53.         UNITY_SETUP_INSTANCE_ID(v);
    54.         UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    55.         TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
    56.         return o;
    57.     }
    58.  
    59.     float4 fragShadow( v2f i ) : SV_Target
    60.     {
    61.         SHADOW_CASTER_FRAGMENT(i)
    62.     }
    63.    
    64.     ENDCG
    65.        
    66.     SubShader
    67.     {
    68.         Stencil
    69.         {
    70.             Ref [_Stencil]
    71.             ReadMask [_ReadMask]
    72.             WriteMask [_WriteMask]
    73.             Comp [_StencilComp]
    74.             Pass [_StencilOp]
    75.             Fail [_StencilFail]
    76.             ZFail [_StencilZFail]
    77.         }
    78.  
    79.         Pass
    80.         {
    81.             Tags { "RenderType"="Opaque" "Queue" = "Geometry" }
    82.             LOD 100
    83.             Cull [_Culling]
    84.             Offset [_Offset], [_Offset]
    85.             ZWrite [_ZWrite]
    86.             ColorMask [_ColorMask]
    87.            
    88.             CGPROGRAM
    89.             #pragma target 3.0
    90.             #pragma vertex vert
    91.             #pragma fragment frag
    92.             ENDCG
    93.         }
    94.        
    95.         // Pass to render object as a shadow caster
    96.         Pass
    97.         {
    98.             Name "ShadowCaster"
    99.             LOD 80
    100.             Tags { "LightMode" = "ShadowCaster" }
    101.             Cull [_Culling]
    102.             Offset [_Offset], [_Offset]
    103.             ZWrite [_ZWrite]
    104.             ColorMask [_ColorMask]
    105.            
    106.             CGPROGRAM
    107.             #pragma vertex vertShadow  
    108.             #pragma fragment fragShadow
    109.             #pragma target 2.0
    110.             #pragma multi_compile_shadowcaster
    111.             ENDCG
    112.         }
    113.     }
    114. }

    Any idea what is going on? Seems like a bug to me...
     
    Afroman likes this.
  6. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    826
    Alright, was just a typo. Sometimes you just need to look at it with a fresh mind...

    Implemented a simple cutout shader which shows all introduced properties:
    upload_2018-2-26_22-55-16.png

    This is really cool for trying out different effects, e.g. using blending and color masking with opaque objects, didn't really think of that before :)

    Any ideas/suggestions what else could be useful to expose?
     
  7. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    826
    Even though I didn't post here, I did work quite a bit on the shader project.
    The project now supports Unity Packages and has the complete suite of opaque, cutout and transparent shaders with lit and unlit versions. Recently I also added a WorldNormal shader and Depth shader for easy debugging.
    Additionally, the Cutout Shader now supports Alpha to Coverage after reading the awesome article by @bgolus .




    The next step I want to take is to fully support Single Pass Stereo Rendering for VR. I'm wondering which builtin shader is a good reference for that, and do I need to use any special multicompiles? Would love to hear from someone who has already gone through the process!

    Otherwise I'm also always happy to get feedback and always open for new ideas :)

    Cheers
    Johannes
     
    bgolus likes this.
  8. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    826
    Just published version 0.6.2, now with support for instanced stereo rendering



    I think the package now provides a really solid foundation for experimenting as well as usage in production. Maybe the standard shader needs more slots (like normal map, roughness & metalness map and so on). Do you miss anything?

    Cheers
    Johannes
     
    Olmi and tng2903 like this.
  9. fakegood

    fakegood

    Joined:
    Oct 11, 2013
    Posts:
    31
    Hello, I would like to know how can I support masking for UI? I've tried setting Stencil ID but it seems that's not enough to compare with the stencil buffer.. I was using Configurable/UI shader with Unity's Mask component on an Image component.
     
  10. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    826
    Hey there!

    Oh very interesting, I didn't try that and noticed, that naming is different with unity Stencil Property. I fixed the problem and pushed a new version: https://github.com/supyrb/ConfigurableShaders/releases/tag/0.7.1

    I also added an UI Example scene in which I use the regular mask in one example, and in the other example I do an inverse mask with the properties provided. I guess that should cover your cases, right?
    Thanks for your contribution!

    upload_2020-4-22_9-34-6.png

    Best
    Johannes
     
  11. fakegood

    fakegood

    Joined:
    Oct 11, 2013
    Posts:
    31
    yeap! that's awesome! will test it out again later today. Thanks for the update :)
     
  12. Noisecrime

    Noisecrime

    Joined:
    Apr 7, 2010
    Posts:
    2,054
    Cool Project, couple of points of interest.

    Unity already has a good number of MaterialPropertyDrawers ( Toggle, PowerSlider, IntRange, Enum, EnumKeyword etc ) that can be seen on this surprisingly good, for Unity, documentation page - MaterialPropertyDrawers, so you could probably streamline your code a bit. At a glance I saw you had a custom toggledrawer etc.

    I'm a little confused though as I found it when searching for a toggle I had in one of my old shaders called [MaterialToggle], yet the docs only mention [Toggle]. Still investigating whats going on with that.

    Also Unity already has an enumeration for colorwritemask - UnityEngine.Rendering.ColorWriteMask


    Question.
    I stumbled onto this thread as I'd encountered a weird issue with setting the default values of enumerations, whereby some of them fail to use the default value when creating a new material. Specifically ZWrite and the Blend src/dst. I have a shader set up so blends are meant to default to srcAlpha and OneMinusSrcAlpha, but in a new material they become One and Zero, while zWrite is meant to default to off, but is always on.

    Edit:
    Ok I'm just being dumb. Even though I'm creating a new material each time, Unity defaults a material to Standard shader. The standard shader uses the same enum property names as I do in my shaders ( made sense to keep consistency ), which means the Standard shader is setting these values, which Unity will cache in the material and its default is opaque render queue, thus why blend and zwrite are set to the values I was seeing.

    To confirm everything is working correctly all I needed to do was change the shader, then click the 'reset' option from the material dropdown and my shader defaults were used.

    Its a bit of a pain and annoying that a New Material ends up with the standard defaults and that it can adversely affect new shaders assigned to it.

    I guess if I wanted to avoid it I could rename all my shader enumerations so they don't match Unity's, but then you lose consistency which might be even more annoying should you edit material parameters in code.

    Probably a more viable solution would be to create MaterialEditors for my Shaders and have it auto-reset. Though of course there will inevitably be times when you don't want to reset and its more code to write.
     
    Last edited: Jul 20, 2020
  13. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    826
    Hi @Noisecrime,

    thanks for your feedback!

    Indeed, Unity has quite a few MaterialPropertyDrawers, but none of them are the same as the ones I implemented (only the toggle is similar). Take a look at the wiki to get more information on them: https://github.com/supyrb/ConfigurableShaders/wiki/PropertyDrawers

    The big difference for the toggle is to avoid generating shader variants through shader keywords, which is the big goal of ConfigurableShaders: To show how to get away with having as little shaders & shader variants as possible, while making them quite customizable.

    Yes, but most of the time I want an RGB (14) ColorMask, which is not a on option of Unity's enum. That's why I chose not to use Unity's enum for that :)
     
    IceTrooper and Noisecrime like this.