GLSL break命令

Col*_*tru 6 shader glsl

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

for (int i = 0; i < uNumLights; i++)
{
   ...............
}
Run Code Online (Sandbox Code Playgroud)

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

for (int i = 0; i < MAX_LIGHTS; i++)
{
    if(i >= uNumLights)
        break;
    ..............
}
Run Code Online (Sandbox Code Playgroud)

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

Dam*_*mon 13

GLSL可能会让for()你感到困惑,因为必须有条件分支,即使没有条件分支,因为硬件根本无法完成(这同样适用if()).

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

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

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

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

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

  • @Steven2163712:HAL = 硬件抽象层(如果您认为这是指科幻电影,请不要开玩笑)。我可能没有使用官方正确的词(尽管我认为它在技术上是正确的)。OpenGL 是一个抽象的东西,它广泛地独立于它下面的实际硬件的功能。这既令人敬畏又令人不安。就好像某些东西不受支持一样棒极了,抽象层只是让它工作(如果可能的话)。烦人,因为您很难获得快速的工作路径,而更难_知道_。 (4认同)