如何在GLSL中正确声明一个统一的结构数组,以便我可以指向它的UBO?

时间:2015-02-11 01:00:38

标签: opengl glsl

以下glsl代码出现在我的片段着色器中。结构定义没有问题,但是我尝试将它用作统一数组的类型会导致"无效操作"错误,这不是特别有帮助。

struct InstanceData
{
    vec3 rotation;
    vec3 scale;
    mat4 position;
};

layout (std140) uniform InstanceData instances[100];

如何正确构造此代码以使其无错误地编译,从而为我填充数据做好了准备?请注意,我使用的是核心配置文件版本4.5。

修改:这似乎与使用layout (std140)有关。删除该部分允许代码编译,但我不需要这样做以确保glsl编译器以可预测的方式打包结构数据?

修改:仍然无效。我的整个顶点着色器代码如下所示:

#version 450

layout(location=0) in vec4 in_Position;
layout(location=1) in vec4 in_Color;
out vec4 ex_Color;
flat out int ex_Instance;

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

// ------ preliminary addition of uniform block to be used soon ------
struct layout (std140) InstanceData
{
    vec3 rotation;
    vec3 scale;
    mat4 position;
};

layout (std140, binding = 0) uniform InstanceData
{
    InstanceData instances[100];
};
// -------------------------------------------------------------------

void main(void)
{
    gl_Position = (projectionMatrix * viewMatrix * modelMatrix) * in_Position;
    ex_Color = in_Color;
}

请注意,我还没有在外部编写任何代码来填充统一缓冲区,正如您在上面所看到的那样,我也没有调整代码来使用数据。我只是希望它按原样编译和工作(即声明但未使用),此时我将添加其他代码以开始使用它。如果程序不喜欢开头的声明,那么即使到目前为止也没有意义。

编辑:最后使用着色器信息日志解决了问题,如下所示:

GLint infoLogLength;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar* strInfoLog = new GLchar[infoLogLength + 1];
glGetShaderInfoLog(id, infoLogLength, NULL, strInfoLog);

简而言之,正如Anton所说,我错误地使用了layout,而我的统一块与我的结构名称相同,为编译器带来了各种各样的混淆。

1 个答案:

答案 0 :(得分:2)

为了便于移植,您应该使用统一缓冲区对象。

目前,您的struct使用3 + 3 + 16 = 22个浮点组件,并且您正在尝试构建一个包含100个这些组件的数组。 OpenGL实现只需要在任何阶段支持1024个浮点统一组件,并且您的阵列需要2200。

统一缓冲区对象允许您存储最多64 KiB(最小)的数据;远远超过上述限制。但是,在使用UBO时需要注意数据对齐,这就是您尝试使用的layout (std140)限定符。

struct InstanceData
{
    vec3 rotation;
    vec3 scale;
    mat4 position;
};

// Uniform block named InstanceBlock, follows std140 alignment rules
layout (std140, binding = 0) uniform InstanceBlock {
  InstanceData instances [100];
};

上面的结构未正确对齐std140,使用它时需要小心。

这就是数据的实际布局方式:

struct InstanceData
{
  vec3  rotation;  // 0,1,2
  float padding03; // 3

  vec3  scale;     // 4,5,6
  float padding07; // 7

  mat4  position;  // 8-23
} // Size: 24 * sizeof (float)

vec3类型与GLSL中的vec4相同,mat4实际上是4 vec4的数组,因此这意味着它们都需要在4开始浮动边界。 GLSL自动插入填充以满足这些对齐规则;我上面所做的更改是为了向您展示在C中编写此数据结构的正确方法。 您必须在结构中考虑2个浮点数的隐式填充。 < / p>


关于编辑,在开始使用缓冲区对象之前,您不必担心GLSL如何打包struct

如果不使用统一缓冲区对象,则必须使用glUniform3f (...)之类的函数来设置制服。这些函数不直接向您公开数据结构,因此打包无关紧要。要设置实例N的值,您可以使用“实例[N] .rotation”和“实例[N] .scale”的位置以及“实例glUniform3f (...)来调用glUniformMatrix4fv (...) [N] .POSITION”。

这需要300个API调用来初始化你的结构的所有100个实例,这样你就可以看到为什么UBO更实用(甚至忽略了上面提到的1024限制)。