我正在查看使用着色器的 OpenGL 应用程序的源代码。一个特定的着色器如下所示:
uniform float someConstantValue;
void main()
{
// Use someConstantValue
}
统一从代码中设置一次,并且在整个应用程序运行时永远不会更改。
在什么情况下我想声明someConstantValue
为 auniform
而不是 as const float
?
编辑: 澄清一下,常数值是一个物理常数。
巨大的原因:
错误:循环索引无法与非常量表达式进行比较。
如果我使用:
uniform float myfloat;
...
for (float i = 0.0; i < myfloat; i++)
我收到一个错误,因为myfloat
不是constant expression
.
然而,这是完全有效的:
const float myfloat = 10.0;
...
for (float i = 0.0; i < myfloat; i++)
为什么?
当 GLSL(以及与此相关的 HLSL)被编译为 GPU 汇编指令时,循环以非常冗长的方式展开(但使用跳转等进行了优化)。这意味着该
myfloat
值在编译时用于展开循环;如果该值是 auniform
(即可以更改每个渲染调用),则该循环在运行时才能展开(并且 GPU 不会进行这种 JustInTime 编译,至少在 WebGL 中不会)。
首先,使用制服或常数之间的性能差异可能可以忽略不计。其次,仅仅因为一个值在本质上总是恒定的,并不意味着你总是希望它在你的程序中是恒定的。程序员经常会调整物理值以产生最好看的结果,即使这与现实不符。例如,在某些类型的游戏中,由于重力的加速度通常会增加,以使其节奏更快。
如果您不想在代码中设置统一,您可以在 GLSL 中提供默认值:
uniform float someConstantValue = 12.5;
也就是说,没有理由不将 const 用于 pi 之类的东西,因为修改它的价值不大......
我可以想到两个原因:
开发人员在多个应用程序中重用了一个着色器库。因此,开发人员没有为每个应用程序定制每个着色器,而是试图保持它们的通用性。
开发人员预计此变量稍后将成为用户控制的设置。因此,将其声明为制服是为即将推出的功能做准备。
如果我是开发人员并且以上都不适用,那么我会将其声明为“const”,因为它可以带来性能优势,并且我不必从我的代码中设置统一。