3

我看到一个问题,我得到错误大小的 GLSL 统一块。

这是着色器中的块:

uniform MaterialInfo {
    vec3 Ka;
    vec3 Ks;    
    vec3 Kd;
};

然后使用以下代码准备我的统一缓冲区对象:

blockIndex = glGetUniformBlockIndex(program, "MaterialInfo");
 if (blockIndex == -1) {
   fprintf(stderr, "Could not bind uniform block\n");
}

printf("Found blockindex materialinfo: %d\n", blockIndex);

 glGetActiveUniformBlockiv(program, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
 blockBuffer = (GLubyte *) malloc(blockSize);
 cout << "GLSL blocksize: " << blockSize << endl;
 cout << "sizeof glm::vec3 type: " << sizeof(mesh->Ka) << endl;
 cout << "sizeof 3 x glm::vec3 type: " << 3 * sizeof(mesh->Ka) << endl;

报告如下:

GLSL blocksize: 48
sizeof glm::vec3 type: 12
sizeof 3 x glm::vec3 type: 36

总之,我期望 GLSL 块大小为 36,而不是 48。GLSL 中的 vec3 应该像我的 glm::vec3 类型一样是浮点数。

另请注意,我使用的是 HD4000 测试版驱动程序:OpenGL 4.0.0 Build 9.17.10.2792。我没有机会在另一台计算机上进行测试。这是我误会了什么吗?

回复后跟进:

所以在这种情况下,提交我的 glm::vec3 浮点数的正确方法如下?

glGetUniformIndices(program, 3, namesMaterial, indices);
glGetActiveUniformsiv(program, 3, indices, GL_UNIFORM_OFFSET, offset);

memcpy(blockBuffer + offset[0], glm::value_ptr(mesh->Ka), 4 * sizeof(GLfloat));
memcpy(blockBuffer + offset[1], glm::value_ptr(mesh->Ks), 4 * sizeof(GLfloat));
memcpy(blockBuffer + offset[2], glm::value_ptr(mesh->Kd), 4 * sizeof(GLfloat));
4

2 回答 2

3

许多 GPU 将每个制服填充为 vec4 的大小:

请参阅 OpenGL wiki 中的此实现说明(重点是我的):

实现说明:OpenGL 实现允许出于实现相关的原因拒绝着色器。因此,根据您的估算,您可以拥有更少的活动统一组件,并且由于统一限制仍然无法链接。这通常发生在完全是矢量硬件的硬件上。Pre GeForce 8xxx 硬件,所有 ATi 硬件都这样做。在这种情况下,您应该假设每个单独的制服占用 4 个组件,就像在 D3D 中一样。这意味着“统一浮点”是 4 个组件,mat2x4 是 16 个组件(每行是 4 个组件),但 mat4x2 是 8 个组件。

于 2012-10-04T20:48:36.563 回答
3

总之,我期望 GLSL 块大小为 36,而不是 48。GLSL 中的 vec3 应该像我的 glm::vec3 类型一样是浮点数。

为什么?OpenGL 规范中没有任何内容可以保证块大小。

或者至少,没有统一块定义。

在不提供适当的内存布局限定符shared情况下,默认使用。这允许实现在元素之间放置它感觉舒适的任何填充。所以你不能只假设 3 vec3s 会占用 12 个连续float的 s 大小。每个vec3将是 3 个连续float的 s,但不能保证不会有填充。

如果您想要统一块的固定、已知和一致的布局,那么您需要使用std140布局。否则,您将得到实现所提供的东西。OpenGL 规范详细说明了std140元素布局的规则。

当然,使用std140布局,这个块的大小也会是 48,因为它会将所有vec3元素填充到vec4s。


所以在这种情况下,提交我的 glm::vec3 浮点数的正确方法如下?

这是正确的,假设:

  1. memoryBlock是映射的缓冲区对象指针或您上传的东西glBufferSubData
  2. 您正在将其上传到缓冲区的前面或适当的偏移量之一(glBindBufferRange 的统一块偏移量必须与 对齐GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT)。
  3. mesh->Ka它的同类实际上做了4次花车。否则,您将从未分配的内存中复制。

再次,我敦促您停止查询这些内容并使用std140布局。当你这样做时,你不必查询偏移量或任何东西;您可以设计与所有硬件上的 GLSL 定义完美布局兼容的结构。

于 2012-10-04T20:52:59.490 回答