Search Unity

avoid low performance with shader_feature

Discussion in 'Shaders' started by ghiboz, Aug 23, 2016.

  1. ghiboz

    ghiboz

    Joined:
    Sep 7, 2012
    Posts:
    465
    hi all! I've got a question:
    to avoid to lose performance and potentially issues I wrote a shader using a
    Code (CSharp):
    1. #pragma shader_feature USE_GROOVE
    shader feature like this, and after in my shader somewhere I've code like this:
    Code (CSharp):
    1. #if defined(USE_GROOVE)
    2.     fixed4 groove = tex2D(_GrooveTex, IN.uv_MainTex);
    3.     o.Albedo = groove;
    4. #else
    5.   o.Albedo = albedo;
    6. #endif
    7.  
    now my question is: it's better create different shaders or use directives like this?
    the only difference that I've is that using directives, make the code lighter, but the declaration is also active (in the example, _GrooveTex is declared, also if I don't use it....

    thanks
     
  2. michal_gjk

    michal_gjk

    Joined:
    Aug 13, 2016
    Posts:
    69
    That depends on how many combinations of features you need. If it's more than, say 4 or 6 then you'll probably find it cumbersome to not only develop manually but also to actually use such set of shaders. On the other hand when using shader_features the number of variants may quickly get out of hand so pay attention. Additionally if you use surface shaders each and every combination will have six auto generated passes regardless if it makes any sens or not.

    Even if you can afford the time to wait for those lengthy compilations to finish it turns out with to many features the compiler simply stops working properly and you'll be forced to split your shader into a few smaller ones because of that anyway.

    At the end of the day you'll probably end up dividing main functionalities into a few separate shaders and then use (just a few) shader_features in each of them to fine tune each variant.

    Obviously even when you split into a few shaders you should keep the bulk of the code in a common .cginc file and only keep the list of features and sometimes hardcoded #defines in those separate shader files.
     
    Last edited: Aug 23, 2016
  3. ghiboz

    ghiboz

    Joined:
    Sep 7, 2012
    Posts:
    465
    thanks again @michal_gjk ,
    my question at the moment is only regarding the performances...
    I'm making a shader that mix until 4 textures albedo/spec and normal and I wish understand if is better have 3 shaders (one mix 2 textures, one mix 3 textures and one mix 4 textures) or one with the #if defined that do the same...
     
  4. michal_gjk

    michal_gjk

    Joined:
    Aug 13, 2016
    Posts:
    69
    You can use #if defined to generate exactly the same code as you would by writing separate shaders so to that end you won't affect the performance negatively however for the variant solution to work you'll need a way to set the keywords in the material. One way is by using [Toggles] it's easy but introduces unnecessary properties. Another way is to set keywords automatically based on which textures are selected. That however will require you to write a custom material editor. If you don't feel like doing all the extra work just write separate shaders. Move all the code with all the #if defs into a .cginc file. In .shader files put only the properties and hardcode the #defines then include the actual code from .cginc. As a bonus this way your shaders will compile much faster than those using shader_features.

    If you need help just paste the code with all the #if defined in it (the all inclusive variant) and I'll help you to split it into separete shaders and an include file.
     
  5. ghiboz

    ghiboz

    Joined:
    Sep 7, 2012
    Posts:
    465
    thanks @michal_gjk !!
    Now I try and after I ask for sure!!