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

Question How can I replace this "if" in my shader?

Discussion in 'Shaders' started by Danebulus, Sep 5, 2020.

  1. Danebulus

    Danebulus

    Joined:
    Jul 3, 2017
    Posts:
    5
    Depending on "_Color.a" I want to lerp the output variable "_InviWabble".
    But I need no simple linear output value.

    So the output value should first start from 0 and rise. Then reaching a maximum, and then decreasing again to a low end value.
    In other words, a kind of lerp() with 3 key points.

    What I want is:
    If _Color.a == 1, then the output (_InviWabble) should be 0.
    If _Color.a == 0.25, then the output (_InviWabble) should be 0.0225.
    If _Color.a == 0, then the output (_InviWabble) should be _WabbleAtInvisible (is approximately at 0.006).

    Therefore I have this code in shader frag():
    if(_Color.a > 0.25)
    _InviWabble = lerp(0.03, 0, _Color.a);
    else
    _InviWabble = lerp(_WabbleAtInvisible, 0.0225, _Color.a*4);


    How can I do the same without the slow "if/else" ?

    Thanks for reading and for every answer :)
     
  2. Oxeren

    Oxeren

    Joined:
    Aug 14, 2013
    Posts:
    120
    This should work just fine. Conditionals are not slow themselves. And in this case, as I understand _Color is a uniform (it comes from a property, right?), so there will be no branch divergence. And even if there were, executing two lerps is not a big deal.
    If you need more control over the output value you can instead sample a gradient texture using _Color.a as uv coordinate.
     
    Danebulus and Olmi like this.
  3. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    You could use lerp and step function to get rid of that if, but I have no real knowledge if it would be any faster, and like Oxeren said, it will most likely nowadays work just fine. And that if-else is much more readable...

    Anyway, something like this:
    (I just simplified your code to an example that visualises the result, using uv x value to drive the test. But you see that the result should be identical.)

    With if:
    Code (HLSL):
    1. float valueA = i.uv.x;
    2. float valueB = 0.006;
    3. fixed4 result = 0;
    4.  
    5. if(valueA > 0.25) {
    6.     result = lerp(0.03, 0, valueA);
    7. }
    8. else {
    9.     result = lerp(valueB, 0.0225, valueA * 4);
    10. }
    Without if:
    Code (HLSL):
    1. result = lerp(
    2.                 lerp(0.03, 0, valueA),
    3.                 lerp(valueB, 0.0225, valueA * 4),
    4.                 step(valueA, 0.25)
    5.              );
     
    Danebulus likes this.
  4. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,469
    Step is still a hidden if, high level language and all ...
     
    Danebulus and Olmi like this.
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    Yeah, @Olmi 's example is basically just adding another lerp, but there's still a conditional. It's the equivalent of doing:
    Code (csharp):
    1. float extraLerpBlend = 0.0;
    2. if(_Color.a > 0.25)
    3.     extraLerpBlend = 1.0;
    4.  
    5. _InviWabble = lerp(
    6.     lerp(_WabbleAtInvisible, 0.0225, _Color.a*4),
    7.     lerp(0.03, 0, _Color.a),
    8.     extraLerpValue);
    Basically, it's slower.*

    What you're doing is already going to be the fastest option. If statements don't mean branches most of the time. It'll be a ternary operator on any modern hardware, which is very fast. Basically it'll do this:
    Code (csharp):
    1. float tempA = lerp(0.03, 0, _Color.a);
    2. float tempB = lerp(_WabbleAtInvisible, 0.0225, _Color.a*4);
    3. _InviWabble = _Color.a > 0.25 ? tempA : tempB;
    On most platforms your original code and that example will compile to identical shaders. And that's fine because there's not really a way to do it faster.


    * except on some old and/or buggy mobile hardware which have really bad shader compilers which prefer step() over ternary operators, even though they should compile to identical code.
     
    Last edited: Sep 6, 2020
    Ian-Snow, Alex-CG and Danebulus like this.
  6. Danebulus

    Danebulus

    Joined:
    Jul 3, 2017
    Posts:
    5
    Thank you all very much :)