GLSL:用缓冲区或纹理替换大型统一int数组

时间:2013-12-18 00:04:12

标签: c++ opengl fragment-shader

现在我正在尝试将一个int数组传递给片段着色器,并通过一个统一的数组执行此操作:

uniform int myArray[300];

使用glUniform1iv将其填充到着色器外部。

不幸的是,大于~400的统一数组失败了。我理解我可以使用“统一缓冲区”,但似乎无法找到将大型1D数组传递到带缓冲区的片段着色器的完整示例。

有人可以提供这样的例子吗?

1 个答案:

答案 0 :(得分:9)

这应该让您开始使用Uniform Buffer Object来存储数组。请注意,GL要求UBO的最小容量为16 KiB,可以通过GL_MAX_UNIFORM_BLOCK_SIZE查询最大容量。

样本片段着色器(UBO需要OpenGL 3.1):

#version 140 // GL 3.1

// Arrays in a UBO must use a constant expression for their size.
const int MY_ARRAY_SIZE = 512;

// The name of the block is used for finding the index location only
layout (std140) uniform myArrayBlock {
  int myArray [MY_ARRAY_SIZE]; // This is the important name (in the shader).
};

void main (void) {
  gl_FragColor = vec4 ((float)myArray [0] * 0.1, vec3 (1.0));
}

OpenGL代码

const int MY_ARRAY_SIZE = 512;

GLuint myArrayUBO;
glGenBuffers (1, &myArrayUBO);

// Allocate storage for the UBO
glBindBuffer (GL_UNIFORM_BUFFER, myArrayUBO);
glBufferData (GL_UNIFORM_BUFFER, sizeof (GLint) * MY_ARRAY_SIZE,
              NULL, GL_DYNAMIC_DRAW);

[...]

// When you want to update the data in your UBO, you do it like you would any
//   other buffer object.
glBufferSubData (GL_UNIFORM_BUFFER, ...);

[...]

GLuint myArrayBlockIdx = glGetUniformBlockIndex (GLSLProgramID, "myArrayBlock");

glUniformBlockBinding (GLSLProgramID,     myArrayBlockIdx, 0);
glBindBufferBase      (GL_UNIFORM_BUFFER, 0,               myArrayUBO);

我可能忘了什么,有理由我不写教程。如果您在执行此操作时遇到任何问题,请发表评论。

更新

请注意,glUniformBlockBinding (...)glBindBufferBase (...)中使用的 0 是绑定点的全局标识符。当与std140布局结合使用时,这意味着您可以在任何GLSL程序中使用此UBO,在该程序中将其统一块之一绑定到该绑定位置( 0 )。当你想在几十个不同的GLSL程序之间共享类似你的ModelView和Projection矩阵时,这实际上非常方便。