C++ GLSL:用缓冲区或纹理替换大的统一整数数组

C++ GLSL:用缓冲区或纹理替换大的统一整数数组,c++,opengl,fragment-shader,C++,Opengl,Fragment Shader,现在,我正在尝试将一个int数组传递到片段着色器中,并通过一个统一数组执行此操作: uniform int myArray[300]; 并在着色器外部填充glUniform1iv 不幸的是,大于~400的统一阵列失败。我知道我可以使用“统一缓冲区”来代替,但似乎找不到一个完整的示例,说明如何使用缓冲区或其他方式将大型1D数组传递到片段着色器中 有人能提供这样一个例子吗?这应该让您开始使用统一缓冲区对象来存储数组。请注意,德国劳埃德船级社要求UBO的最小容量为16千磅,可通过GL\u MAX\u

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

uniform int myArray[300];
并在着色器外部填充
glUniform1iv

不幸的是,大于
~400
的统一阵列失败。我知道我可以使用“统一缓冲区”来代替,但似乎找不到一个完整的示例,说明如何使用缓冲区或其他方式将大型1D数组传递到片段着色器中


有人能提供这样一个例子吗?

这应该让您开始使用统一缓冲区对象来存储数组。请注意,德国劳埃德船级社要求UBO的最小容量为16千磅,可通过
GL\u MAX\u UNIFORM\u BLOCK\u SIZE
查询最大容量

示例片段着色器(UBOs需要OpenGL 3.1): OpenGL代码 我可能忘了什么,我不写教程是有原因的。如果您在实现此功能时遇到任何问题,请留下评论

更新:
请注意,在
glUniformBlockBinding(…)
glBindBufferBase(…)
中使用的0是绑定点的全局标识符。当与
std140
布局一起使用时,这意味着您可以在任何GLSL程序中使用此UBO,其中您可以将其统一块之一绑定到该绑定位置(0)。当您想在几十个不同的GLSL程序之间共享模型视图和投影矩阵时,这实际上非常方便。

@Vallentin-5行示例代码不是教程。您的目标是什么版本的GL,您希望此数组具有可变长度吗?使用统一缓冲区对象(GL 3.1)是正确的,它们允许存储更大的数组,但不能具有可变长度。如果需要可变长度,可以使用名为着色器存储缓冲区对象(GL 4.3)的较新功能。现在,既然您在标签中提到了OpenGL ES,我必须指出,唯一真正可移植的解决方案可能是纹理查找。即使如此,在GL ES 2.0中,顶点纹理查找也是一个可选功能,因此这可能会限制您使用片段。@AndonM.Coleman-我使用的是4.1。如果它们可以是可变长度的,那就更好了,但我也可以使用固定长度的解决方案。非常感谢。好的,你有什么理由在你的问题中包含OpenGL ES标签吗?如果您不需要支持ES,或将ES 3.0作为您的最低ES版本,则UBOs将正常工作。@AndonM.Coleman-对于标签,很抱歉,这不是我的意图。你能展示一个大数组的UBO示例吗?通常最好在统一块中添加
int size
,以存储实际使用的元素数量,因为数组大小通常是上限。(仅为了示例:)看起来OSX10.9不喜欢着色器代码,可能是因为它使用的是GLSL的旧版本。不幸的是,我正在使用openFrameworks,我不太确定如何强制它使用更高版本。这个答案中根本没有提到纹理。是因为(每个人都知道)纹理明显比UBO慢吗?
#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));
}
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);