GLSL优化:检查变量是否在范围内

时间:2018-10-23 21:36:18

标签: opengl glsl

在我的着色器中,我有变量b,需要确定它位于哪个范围内,并从中为变量a分配正确的值。我最后得到了很多if语句:

    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;
    }

我的问题是,这是否会导致性能问题(分支),我该如何对其进行优化?我已经看过了step和smoothstep函数,但是还没有找到一种很好的方法来实现这一点。

3 个答案:

答案 0 :(得分:2)

您可以通过创建查找表来避免分支:

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

但是性能将取决于是否必须在每个着色器中创建查找表,或者它是否是某种统一的...与往常一样,请首先进行测量...

答案 1 :(得分:2)

要解决所描述的问题并避免分支常规技术,那就是找到一系列数学函数,每个条件一个,对于变量不满足的所有条件,所有条件求值为0。我们可以使用这些函数作为收益来建立每次求和都正确值的总和。 在这种情况下,条件是简单的间隔,因此,使用step函数,我们可以编写:

x在[a,b]中为step(a,x)*step(x,b)(请注意x和b的求反得到x <= b)

如另一篇文章所述,在[a,b [中以step(a,x)-step(x,b)的形式出现

x,GLSL point inside box test

使用此技术,我们可以获得:

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

这适用于一般的不相交的间隔,但是对于此问题中的阶梯或阶梯功能,我们可以将其简化为:

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)

我们还可以使用“布尔转换为浮点数”来表达我们的条件,例如,step(8.0,x)*(const5-const4)等效于float(x>=8.0)*(const5-const4)

答案 2 :(得分:0)

事实证明,Jaa-cs答复对我而言不可行,因为我的目标是WebGL,WebGL不允许变量作为索引(除非它是循环索引)。不过,他的解决方案可能对其他OpenGL实现很有用。

我想出了使用混合和阶跃函数的解决方案:

//Outside of main function:
uniform vec3 constArray[5]; // Values are sent in to shader

//Inside main function:
float a = constArray[0];
a = mix(a, constArray[1], step(2.0, b));
a = mix(a, constArray[2], step(4.0, b));
a = mix(a, constArray[3], step(6.0, b));
a = mix(a, constArray[4], step(8.0, b));

但是经过一些测试,它并没有任何明显的性能提升。我终于有了这个解决方案:

float a = constArray[0];

if (b >= 2.0)
    a = constArray[1];
if (b >= 4.0)
    a = constArray[2];
if (b >= 6.0)
    a = constArray[3];
if (b >= 8.0)
    a = constArray[4];

既紧凑又易于阅读。就我而言,这些替代方法和原始代码的性能均相同,但是至少可以尝试一些选择。