在 OpenGL 着色器中在 main 之外进行计算是否合理?

Is it ever reasonable to do computations outside of main in an OpenGL shader?

我有一些类似于下面的顶点着色器代码(这是一个简化的示例):

attribute vec2 aPosition;
attribute vec4 aColor;

varying lowp vec4 vColor;

uniform  vec4 uViewport;
mat4 viewportScale = mat4(2.0 / uViewport.z, 0, 0, 0,    0, -2.0 / uViewport.w, 0,0,    0, 0,1,0,    -1,+1,0,1);

void main() {
  vec2 pos = aPosition;
  gl_Position = viewportScale * vec4(pos, 0, 1);
  vColor = vec4(aColor.rgb*aColor.a, aColor.a);
}

特别地,viewportScale矩阵是从主函数之外的uViewport均匀计算出来的。从浏览器 (WebGL) 使用它,它似乎在我测试过的每台机器上都能正常工作……特别是,当我更改 uViewport 变量时,viewportScale 矩阵会正确更新。这样做和在 main 函数内部进行相同的计算有什么区别吗?我找不到与此相关的任何示例或讨论。

我 运行 进入 related problem 这让我对这个问题有点厌恶 运行 -- 至少,我想了解发生了什么.

这不是 GLSL ES 1.00 中的合法着色器,它是与 ES 2.0 一起使用的 GLSL 版本。 WebGL 共享相同的 GLSL 定义,但 WebGL 规范中指定了一些例外情况。我在 WebGL 规范中找不到这个例外,所以我认为着色器在 ES 2.0 和 WebGL 中都是非法的。

来自 GLSL ES 1.00 规范,第 29 页的“4.3 存储限定符”部分(添加了重点):

Declarations of globals without a storage qualifier, or with just the const qualifier, may include initializers, in which case they will be initialized before the first line of main() is executed. Such initializers must be a constant expression.

第 49 页的“5.10 常量表达式”部分定义了常量表达式是什么。它包括:

The following may not be used in constant expressions:

  • Uniforms, attributes and varyings.

你的例子中的表达式包含一个制服,这使它成为一个非常量表达式。因此它不能用作全局变量的初始值设定项。

我 运行 在我的 Android 申请中遇到了这个问题。

我在片段着色器的主块外部使用统一变量定义了一个变量。

uniform u_rotation;
mat2 rotation = mat2(cos(u_rotation), sin(u_rotation), -sin(u_rotation), cos(u_rotation)); 
void main() {}

这个片段着色器在除一台 Nexus 6 之外的所有 Android 设备上运行良好。奇怪的是我有两台 Nexus 6,一台每次都崩溃,另一台大部分时间都得到错误的结果。