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

nbu*_*bis 8 c++ opengl fragment-shader

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

uniform int myArray[300];
Run Code Online (Sandbox Code Playgroud)

并在着色器外面填充它glUniform1iv.

不幸的是,大于~400失败的统一阵列.我知道我可以使用"统一缓冲区",但似乎无法找到将大型1D数组传递到带缓冲区或其他方式的片段着色器的完整示例.

谁能提供这样的例子?

And*_*man 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));
}
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

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

更新:

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