设置第二个顶点数组对象会导致奇怪的渲染

Setting up a second vertex array object has led to odd rendering

本文关键字:顶点 第二个 数组 对象 设置      更新时间:2023-10-16

所以我有几个类。一个渲染器和box2drenderer。现在它们都使用自己的顶点缓冲区和顶点数组对象。Renderer首先用下面的代码实例化:

glGenBuffers(1, &ebo);
glGenBuffers(1, &vbo);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
GLfloat vertices[] = {
    //  Position(2) Color(3)     Texcoords(2)
    0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, // Top-left
    1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, // Top-right
    1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // Bottom-right
    0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f  // Bottom-left
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
GLuint elements[] = {
    0, 1, 2,
    2, 3, 0
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), 0);
GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(5 * sizeof(GLfloat)));
glBindVertexArray(0);
glUseProgram(shaderProgram);
projection = glm::ortho(0.0f, width, height, 0.0f);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUseProgram(0);

然后我为box2d调用setup函数:

void Box2DRenderer::setRenderer(Renderer * r) {
    this->renderer = r;
    const GLchar * fragSource =
    "#version 150 coren
    precision mediump float;n
    uniform vec4 u_color;n
    out vec4 Color;n
    n
    void main()n
    {n
      Color = u_color;n
    }";
    const GLchar * vertSource =
    "#version 150 coren
    uniform mediump mat4 u_projection;n
    uniform mediump float u_pointSize;n
    in vec2 a_position;n
    n
    void main()n
    {n
      gl_PointSize = u_pointSize;n
      gl_Position = u_projection * vec4(a_position, 0.0, 1.0);n
    }";
    this->renderer->compileProgram(vertSource, fragSource, vertShader, fragShader, shaderProgram);
    glUseProgram(shaderProgram);
    glGenBuffers(1, &vbo);
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
    glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "u_projection"), 1, GL_FALSE, glm::value_ptr(this->renderer->getProjectionMatrix()));
    GLuint positionLocation = glGetAttribLocation(shaderProgram, "a_position");
    glEnableVertexAttribArray(positionLocation);
    glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
    glBindVertexArray(0);
    colorLocation = glGetUniformLocation(shaderProgram, "u_color");
    pointSizeLocation = glGetUniformLocation(shaderProgram, "u_pointSize");
    glUseProgram(0);
}

渲染器现在只是绘制纹理。所以我通过

方法绘制玩家
void Renderer::renderTexture(sf::FloatRect &bounds, Texture &texture, Region *region) {
    glm::mat4 model;
    model = glm::translate(model, glm::vec3(bounds.left, bounds.top, 0.0f));
    model = glm::scale(model, glm::vec3(bounds.width, bounds.height, 0.0f));
    GLint modelMat = glGetUniformLocation(shaderProgram, "mMatrix");
    glUniformMatrix4fv(modelMat, 1, GL_FALSE, glm::value_ptr(model));
    float x = region->pos.x / texture.getWidth();
    float y = region->pos.y / texture.getHeight();
    float rx = (region->width + region->pos.x) / texture.getWidth();
    float ry = (region->height + region->pos.y) / texture.getHeight();
    GLfloat vertices[] = {
        //  Position(2) Color(3)     Texcoords(2)
        0.0f, 0.0f, 1.0f, 1.0f, 1.0f, x, y, // Top-left
        1.0f, 0.0f, 1.0f, 1.0f, 1.0f, rx, y, // Top-right
        1.0f, 1.0f, 1.0f, 1.0f, 1.0f, rx, ry, // Bottom-right
        0.0f, 1.0f, 1.0f, 1.0f, 1.0f, x, ry  // Bottom-left
    };
    glBindTexture(GL_TEXTURE_2D, texture.getTextureId());
    glBindVertexArray(vao);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
    glBindTexture(GL_TEXTURE_2D, 0);
}

现在,如果我不初始化box2d渲染器,它工作良好。如果我有box2d渲染器,纹理线会变得混乱。整个纹理似乎是在屏幕上绘制的,而不是在正确的位置绘制区域。

给定我打开和关闭BindVertexArray,我觉得我不应该有问题,但对于我的生活我不能弄清楚。如果你愿意,我可以把它们的区别截图出来。

您可能遇到了一个相当普遍的误解:与您所期望的相反,GL_ARRAY_BUFFER绑定是而不是 VAO状态的一部分。

在发布的代码的尾部,你有这样的序列:

glBindVertexArray(vao);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);

glBufferSubData()调用将修改当前绑定的GL_ARRAY_BUFFER中的数据,这是您上次进行glBindBuffer(GL_ARRAY_BUFFER, ...)调用的缓冲区。这与您之前使用VAO时绑定的缓冲区无关。

为了进一步说明,下面是一个典型的调用序列:
glBindVertexArray(vaoA);
glBindBuffer(GL_ARRAY_BUFFER, vboA);
glBindVertexArray(vaoB);
glBindBuffer(GL_ARRAY_BUFFER, vboB);
glBindVertexArray(vaoA);

当前在该序列末尾的GL_ARRAY_BUFFER绑定是vboB。由于绑定不是VAO状态的一部分,它只是基于最近的glBindBuffer()调用。

你所需要做的就是在glBufferSubData()之前添加glBindBuffer()调用。

注意GL_ELEMENT_ARRAY_BUFFER绑定是VAO状态的一部分。这可能看起来不一致,但事实并非如此。VAO捆绑了绘制命令使用的所有顶点设置状态。GL_ELEMENT_ARRAY_BUFFER绑定控制绘制命令使用哪个索引缓冲区,因此它是该状态的一部分。另一方面,当前的GL_ARRAY_BUFFER绑定对draw命令没有影响,因此不是VAO状态的一部分。
相关文章: