Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GLSL optimization: check if variable is within range

In my shader I have variable b and need to determine within which range it lies and from that assign the right value to variable a. I ended up with a lot of if statements:

    float a = const1;

    if (b >= 2.0 && b < 4.0) {
        a = const2;
    } else if (b >= 4.0 && b < 6.0) {
        a = const3;
    } else if (b >= 6.0 && b < 8.0) {
        a = const4;
    } else if (b >= 8.0) {
        a = const5;
    }

My question is could this lead to performance issues (branching) and how can I optimize it? I've looked at the step and smoothstep functions but haven't figured out a good way to accomplish this.

like image 595
Johan Avatar asked Sep 14 '25 22:09

Johan


2 Answers

To solve the problem depicted and avoid branching the usual techniques is to find a series of math functions, one for each condition, that evaluate to 0 for all the conditions except the one the variable satisfies. We can use these functions as gains to build a sum that evaluates to the right value each time. In this case the conditions are simple intervals, so using the step functions we could write:

x in [a,b] as step(a,x)*step(x,b) (notice the inversion of x and b to get x<=b)

Or

x in [a,b[ as step(a,x)-step(x,b) as explained in this other post: GLSL point inside box test

Using this technique we obtain:

float a = (step(x,2.0)-((step(2.0,x)*step(x,2.0)))*const1 + 
                (step(2.0,x)-step(4.0,x))*const2 + 
                (step(4.0,x)-step(6.0,x))*const3 + 
                (step(6.0,x)-step(8.0,x))*const4 + 
                step(8.0,x)*const5

This works for general disjoint intervals, but in the case of a step or staircase function as in this question, we can simplify it as:

float a = const1 + step(2.0,x)*(const2-const1) +
                   step(4.0,x)*(const3-const2) +
                   step(6.0,x)*(const4-const3) +
                   step(8.0,x)*(const5-const4)

We could also use a 'bool conversion to float' as means to express our conditions, so as an example step(8.0,x)*(const5-const4) is equivalent to float(x>=8.0)*(const5-const4)

like image 53
AndrewBloom Avatar answered Sep 17 '25 20:09

AndrewBloom


You can avoid branching by creating kind of a lookup table:

float table[5] = {const1, const2, const3, const4, const5};
float a = table[int(clamp(b, 0.0, 8.0) / 2)];

But the performance will depend on whether the lookup table will have to be created in every shader or if it's some kind of uniform... As always, measure first...

like image 35
Jaa-c Avatar answered Sep 17 '25 20:09

Jaa-c