glVertexAttribPointer 覆盖

2021-12-19 00:00:00 opengl c++

我对如何在不同的多个程序之间正确切换感到困惑.我已经将问题缩小到以下几点:如果我用 NO_HDR 运行,它工作正常;我得到了一些线条、一艘太空船和一些球体,按照这个顺序渲染.如果我使用 HDR 运行,我得到的结果大致相同,但我得到的是二维方块而不是球体.

I am confused as to how to properly switch between different multiple programs. I've narrowed the problem down to the following: if I run with NO_HDR, it works fine; I get some lines, a space ship, and some spheres, rendered in that order. If I run with HDR, I get mostly the same thing, but instead of spheres I get 2d squares.

我认为 hdr 部分的四边形顶点属性覆盖了 forwardRender() 部分中要呈现的最后内容.如果我更改 forwardRender() 中的顺序,则 forwardRender() 中最后呈现的任何内容都会以某种方式搞砸.我错过了什么是允许四边形顶点覆盖我的其他对象?

I think the quad vertex attribute from the hdr portion is overwriting the last things to render in the forwardRender() section. If I change the order in forwardRender(), whatever is rendered last in forwardRender() will be messed up in some way. What am I missing that is allowing the quad vertices to overwrite my other objects?

#if NO_HDR
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
forwardRender();

#else

//set to render to custom frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, rt.FramebufferName);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
forwardRender();

//now switch to render to screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, rt.renderedTexture);

glUseProgram(hdr.shaderProgram);
glUniform1i(texID, 0);

glBindBuffer(GL_ARRAY_BUFFER, hdr.quad_vertexbuffer);
glEnableVertexAttribArray(hdr.quad_vertexPosition_modelspace);
glVertexAttribPointer(
                      hdr.quad_vertexPosition_modelspace, // attribute
                      3,                              // size
                      GL_FLOAT,                       // type
                      GL_FALSE,                       // normalized?
                      0,                              // stride
                      (void*)0                        // array buffer offset
                      );
// Draw the triangles !
glBindVertexArray(hdr.vao);
glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles

#endif

另一个线索:如果我在最后的 glDrawArrays 之后禁用 vertexAttribArray,我的球体/正方形就会消失!

Another clue: If I disable the vertexAttribArray after glDrawArrays at the end, my spheres/squares disappear!

作为参考,以下是我在 forwardRender() 中渲染球体的方法:

For reference, here is how I render the spheres in forwardRender():

glUseProgram(globe.shaderProgram);
glm::mat4 mvp = camera * world * position * size * orientation;
GLint uTransform = glGetUniformLocation(shaderProgram, "transform");
glUniformMatrix4fv(uTransform, 1, GL_FALSE, glm::value_ptr(mvp));
glBindVertexArray(globe.vao);
glDrawArrays(drawType, 0, globe.drawCount);

推荐答案

发布的代码表明可能对顶点数组对象 (VAO) 的工作方式存在误解.VAO 是状态的集合.它包含具有以下调用的状态集:

The posted code suggests a possible misunderstanding of how Vertex Array Objects (VAO) work. A VAO is a collection of state. It contains the state set with the following calls:

  • glVertexAttribPointer(...)
  • glEnableVertexAttribArray(...), glDisableVertexAttribArray()
  • glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...)

每当您进行这些调用之一时,相应的状态就会保存在当前绑定的 VAO 中.当您稍后再次绑定 VAO 时,状态会恢复.

Whenever you make one of these calls, the corresponding state is saved in the currently bound VAO. And when you later bind the VAO again, the state is restored.

例如,在发布代码的这个序列中:

For example, in this sequence from the posted code:

glEnableVertexAttribArray(hdr.quad_vertexPosition_modelspace);
glVertexAttribPointer(hdr.quad_vertexPosition_modelspace, ...);
// Draw the triangles !
glBindVertexArray(hdr.vao);
glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles

glDrawArrays() 调用将不使用您在序列中的前两个调用中设置的状态.该状态将应用于当时绑定的任何 VAO.然后,glBindVertexArray(hdr.vao) 调用恢复存储在 hdr.vao 中的状态,这是之前绑定该 VAO 时的最新状态集.

the glDrawArrays() call will not use the state you set up with the first two calls in the sequence. That state will be applied to whatever VAO is bound at the time. Then, the glBindVertexArray(hdr.vao) call restores the state stored in hdr.vao, which is the most recent state set when that VAO was previously bound.

另请注意,这与切换程序无关.顶点状态不是程序状态的一部分.

Also note that this has nothing to do with switching programs. Vertex state is not part of the program state.

要有效地使用 VAO,您的程序结构通常如下所示:

To use VAOs effectively your program structure would typically look like this:

  1. 有一次,在设置过程中,您为每个对象创建了一个 VAO.例如.一个用于您的地球,一个用于四边形等.然后绑定每个 VAO,并从上面的列表中进行调用以设置对象的顶点状态.
  2. 在渲染过程中,对于每个对象,必要时更改程序,绑定对象的 VAO,并进行绘制调用.您不需要任何其他顶点状态调用,因为状态存储在每个对象的 VAO 中.

我认为您的代码中没有这个问题,只是为了强调一个有时会引起混淆的相关项目:正确的 GL_ARRAY_BUFFER 绑定需要在当时就位<代码>glVertexAttribPointer() 被调用.无需为绘制调用建立 GL_ARRAY_BUFFER 绑定.

I don't think you have a problem with this in your code, but just to emphasize one related item that sometimes causes confusion: The correct GL_ARRAY_BUFFER binding needs to be in place at the time glVertexAttribPointer() is called. There is no need to establish GL_ARRAY_BUFFER bindings for the draw calls.

相关文章