GLSL break命令

时间:2011-02-05 11:30:49

标签: glsl shader

目前我正在学习如何在GLSL中为我正在制作的游戏引擎创建着色器,我对这个令我困惑的语言有疑问。我已经了解到,在低于3.0的着色器版本中,您不能在循环条件下使用统一变量。例如,以下代码不适用于早于3.0的着色器版本。

for (int i = 0; i < uNumLights; i++)
{
   ...............
}

但是不可能用一个具有固定迭代量的循环来替换它,但是如果i(在这种情况下,i)大于uNumLights,则包含一个条件语句会破坏循环。例如:

for (int i = 0; i < MAX_LIGHTS; i++)
{
    if(i >= uNumLights)
        break;
    ..............
}

这些不等同吗?后者应该使用旧版本的GLSL吗?如果是这样,这比我读过的其他技术更有效,更容易实现,比如使用不同版本的着色器来获得不同数量的灯光?
我知道这可能是一个愚蠢的问题,但我是一个初学者,我找不到为什么这不起作用的原因。

3 个答案:

答案 0 :(得分:12)

GLSL可能令人困惑,因为for()建议您必须有条件分支,即使没有条件分支,因为硬件根本无法完成(适用于if() in同样的方式)。

在SM3之前的硬件上发生的真正的是,你的OpenGL实现中的HAL将完全展开你的循环,所以实际上没有跳转了。并且,这解释了为什么使用非常数很难做到这一点。

虽然技术上可以使用非常量来实现,但每次更改该制服时,实现都必须重新编译着色器,如果您只是允许提供任何随机数,它可能会违反最大指令数

这是一个问题因为......然后呢?那是一个糟糕的情况。

如果提供的常量太大,则在构建着色器时会给出“太多指令”编译器错误。现在,如果你在制服中提供一个愚蠢的数字,并且HAL因此必须产生新的代码并且在这个限制下运行,那么OpenGL可以做什么呢? 您很可能在编译和链接后验证了您的程序,并且您最有可能查询着色器信息日志,并且OpenGL一直告诉您一切都很好。在某种程度上,这是一个有约束力的承诺,它不能一下子就决定。因此,它必须确保不会出现这种情况,唯一可行的解​​决方案是不允许在不支持动态分支的硬件代的情况下使用制服。
否则,glUniform内部需要进行某种形式的验证,以拒绝不良值。但是,由于这取决于成功(或不成功)着色器重新编译,这意味着它必须同步运行,这使得它成为一种“不行”的方法。另外,请考虑GL_ARB_uniform_buffer_object在某些SM2硬件(例如GeForce FX)上暴露,这意味着您可以在OpenGL中抛出具有不可预测内容的缓冲区对象,并且仍然期望它以某种方式工作!在取消映射后,实现必须扫描缓冲区的内存中的无效值,这是疯了。

与循环类似,if()语句不会在SM2硬件上分支,即使它看起来像。相反,它将计算两个分支并进行有条件的移动。

答案 1 :(得分:2)

(我假设你在谈论像素着色器) 第二个变体仅适用于支持着色器模型&gt; = 3的gpu。因为gpu着色器模型&lt;不支持动态分支(例如将变量 uNumLights 置于IF条件中)。 3要么。

Here您可以比较不同着色器模型之间和不支持的内容。

答案 2 :(得分:0)

我刚刚发现了一个有趣的工作。看起来很愚蠢,我不能向您保证这是一个健康的选择,但它现在似乎对我有用:

将您的 for 循环设置为您允许的最大值。如果计数超出您的统一值,则在循环中放置一个条件以跳过繁重的例程。

uniform int iterations;

for(int i=0; i<10; i++){
     if(i<iterations){
          //do your thing...
     }
}