在 GLSL 中使用 int 时渲染中断

Rendering breaks when using an int in GLSL

我正在为延迟渲染器渲染光球,并且正在切换到实例化以获得更好的性能。我有以下顶点着色器:

in vec3 position;

uniform int test_index;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix[256];

void main(void) {
    gl_Position = projectionMatrix * viewMatrix * modelMatrix[test_index] * vec4(position, 1.0);
}

我使用

将矩阵上传到着色器
val location = glGetUniformLocation(programId, "modelMatrix[$i]")
glUniformMatrix4fv(location, false, buf)

当我在索引中使用 int 制服(出于调试目的硬编码为 0)时,球体消失了,除非我剪辑到几何体中(在这种情况下它呈现为白色圆圈)。当我使用 gl_InstanceID 作为我的索引时,也会发生同样的情况。

奇怪的是,我注意到当我将 int 从顶点传递到片段着色器并将它用于完全不同的东西时,也会出现问题,无论我使用什么作为索引。

当我在着色器中硬编码 modelMatrix[0] 而不是 modelMatrix[test_index] 时,问题立即消失并且渲染完全正常。

我有一个不同的着色器(用于骨骼动画),它以完全相同的方式上传一个 mat4 统一数组,也用一个 int 进行索引,但我没有遇到这样的问题...

我真的不知道该怎么做,所以非常感谢任何关于如何调试它的建议。我在 Kotlin+LWJGL

上使用 OpenGL 3.3

编辑:这可能与制服无关。以下也 not 工作:

int i = 0;
gl_Position = projectionMatrix * viewMatrix * modelMatrix[i] * vec4(position, 1.0f);

OpenGL 对可以使用的制服数量有限制。这同样适用于属性(但这不是这里的问题)。 256个矩阵的数组很可能超出允许的数量。

代码仅在使用 int 统一时中断的原因是 glsl 编译器在后台进行了大量优化,例如,删除未使用的统一。因此,如果您在着色器中对数组位置进行硬编码,编译器会注意到只使用了一个矩阵,并且可能会删除所有其他矩阵。

当您需要比 OpenGL 允许的更多的统一时,您必须使用统一缓冲区对象 (UBO) 或着色器存储缓冲区 (SSBO)。