6

我正在尝试使用着色器存储缓冲区对象(又名缓冲区块),但有几件事我没有完全掌握。我要做的是在其中存储不确定数量的灯光的(简化)数据n,以便我的着色器可以遍历它们并执行计算。

首先让我说我得到了正确的结果,并且没有来自 OpenGL 的错误。然而,它困扰我不知道它为什么工作

所以,在我的着色器中,我得到了以下信息:

struct PointLight {
  vec3 pos;
  float intensity;
};

layout (std430, binding = 0) buffer PointLights {
  PointLight pointLights[];
};

void main() {
  PointLight light;
  for (int i = 0; i < pointLights.length(); i++) {
    light = pointLights[i];
    // etc
  }
}

在我的应用程序中:

struct PointLightData {
  glm::vec3 pos;
  float intensity;
};

class PointLight {
  //  ...
  PointLightData data;
  // ...
};

std::vector<PointLight*> pointLights;

glGenBuffers(1, &BBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, BBO);
glNamedBufferStorage(BBO, n * sizeof(PointLightData), NULL, GL_DYNAMIC_STORAGE_BIT);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, BBO);

...

for (unsigned int i = 0; i < pointLights.size(); i++) {
  glNamedBufferSubData(BBO, i * sizeof(PointLightData), sizeof(PointLightData), &(pointLights[i]->data));
}

在最后一个循环中,我存储了一个PointLightData结构,其偏移量等于它的大小乘以我已经存储的它们的数量(所以0第一个是偏移量)。

所以,正如我所说,一切似乎都是正确的。绑定点正确设置为零,我为我的对象分配了足够的内存等。图形结果还可以。

现在回答我的问题。我正在std430用作布局 - 事实上,如果我将其更改std140为我最初所做的那样,它就会中断。这是为什么?我的假设是std430着色器PointLights缓冲区块生成的布局与编译器为我的应用程序PointLightData结构生成的布局很匹配(正如您在该循环中看到的那样,我一个接一个地存储)。你认为是这样吗?

现在,假设我的假设是正确的,显而易见的解决方案是自己进行大小和偏移量的映射,用glGetUniformIndicesand查询opengl glGetActiveUniformsiv(后者用GL_UNIFORM_SIZEand调用GL_UNIFORM_OFFSET),但我偷偷怀疑这两个家伙只有使用统一块而不是像我正在尝试做的缓冲块。至少,当我执行以下操作时,OpenGL 会发脾气,给我一个1281错误并返回一个非常奇怪的数字作为索引(类似3432898282或其他):

const char * names[2] = { 
  "pos", "intensity"
};

GLuint indices[2];
GLint size[2];
GLint offset[2];

glGetUniformIndices(shaderProgram->id, 2, names, indices);
glGetActiveUniformsiv(shaderProgram->id, 2, indices, GL_UNIFORM_SIZE, size);
glGetActiveUniformsiv(shaderProgram->id, 2, indices, GL_UNIFORM_OFFSET, offset);

我这样说是否正确glGetUniformIndices并且glGetActiveUniformsiv不适用于缓冲块?

如果他们不这样做,或者它工作的事实就像我想象的只是巧合,我怎么能手动进行映射?我检查了编程指南的附录 H,结构数组的措辞有些混乱。如果我无法查询 OpenGL 的大小/偏移量,我想我可以手动计算它们(虽然很麻烦),但我也很感激那里的一些帮助。

4

0 回答 0