繁体   English   中英

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

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

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

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调用设置函数:

void Box2DRenderer::setRenderer(Renderer * r) {
    this->renderer = r;

    const GLchar * fragSource =
    "#version 150 core\n\
    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 core\n\
    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()调用。

所有你需要做的,解决这个问题是添加glBindBuffer()调用之前glBufferSubData()

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM