OpenGL - 重新绑定glBindVertexArray不会向屏幕绘制任何内容

时间:2015-03-14 15:50:29

标签: c++ opengl

我刚刚开始尝试学习opengl,并且正在将代码的各个部分分离到我遇到问题的类中。

这是一个非常简单的问题。在下面的代码中,如果Mesh构造函数底部的glBindVertexArray(0)被注释掉,它会将图像绘制到屏幕上,但如果我将其放入,则不会绘制图像。

glBindVertexArray(vao)函数的glDrawElements调用之前有一个Mesh.draw()命令,所以看起来它应该可行,但它没有。

主要代码:

int main(int argc, char*argv[]) {

    if (SDL_Init(SDL_INIT_VIDEO) < 0)
        std::cout << "SDL did not intizlize.  SDL Error: " << SDL_GetError() << std::endl;

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

    SDL_Window* window = SDL_CreateWindow("OpenGL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL);
    SDL_GLContext context = SDL_GL_CreateContext(window);


    glewExperimental = GL_TRUE;
    GLenum glewTest = glewInit();
    if (glewTest != GLEW_OK)
        std::cout << glewGetErrorString(glewTest) << std::endl;
    std::cout << glGetError() << std::endl;

    Mesh mesh;
    Shaders shaders("basicShader");
    Texture texture("kitten.png");

    //Loop stuff
    bool quit = false;
    SDL_Event e;
    double frameCounter = 0;
    double time = SDL_GetTicks();

    while (!quit) {
        while (SDL_PollEvent(&e)) {
            if (e.type == SDL_QUIT) {
                quit = true;
            }
            if (e.type == SDL_KEYDOWN) {
                if (e.key.keysym.sym == SDLK_ESCAPE)
                    quit = true;
            }
        }

        ++frameCounter;
        if (SDL_GetTicks() - time >= 500) {
            std::cout << "FPS: " << frameCounter / ((SDL_GetTicks() - time) / 1000) << std::endl;
            frameCounter = 0;
            time = SDL_GetTicks();
        }

        // Clear the screen to black
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        mesh.draw();
        //glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        // Swap buffers
        SDL_GL_SwapWindow(window);
    }

    mesh.~Mesh();
    SDL_GL_DeleteContext(context);
    SDL_Quit();
    return 0;
}

网格类代码:

Mesh::Mesh() {
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glGenBuffers(1, &vbo);
    GLfloat vertices[] = {
        -0.5f, 0.5f, 0.0, 0.0,
        0.5f, 0.5f, 1.0, 0.0,
        0.5f, -0.5f, 1.0, 1.0,
        -0.5f, -0.5f, 0.0, 1.0
    };
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glGenBuffers(1, &ebo);
    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);

    //glBindVertexArray(0);
}

void Mesh::draw() {
    glBindVertexArray(vao);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

    //glBindVertexArray(0);
}

Mesh::~Mesh() {
    glDeleteVertexArrays(1, &vao);
}

我也没有在此处发布着色器设置代码,调用glVertexArrayPointer()glEnableVertexAttribArray()来设置顶点属性。

1 个答案:

答案 0 :(得分:3)

问题在于您在设置着色器时进行的glVertexAttribPointer()glEnableVertexAttribArray()调用。这两个调用都会修改当前VAO的状态。

如果你打电话:

glBindVertexArray(0);

在设置网格结束时,0现在是您当前的VAO(兼容性配置文件中的合法VAO,但不在核心配置文件中)。因此,在此之后调用glVertexAttribPointer()glEnableVertexAttribArray()将调用VAO 0中的状态。

当您在draw()方法开始时调用绑定VAO时:

glBindVertexArray(vao);

您正在使用网格VAO中的所有状态。这反过来意味着您没有使用您在VAO 0中设置的状态。由于您在绑定网格VAO时从未进行glVertexAttribPointer()glEnableVertexAttribArray()调用,因此现在根本没有设置顶点属性。

当你没有在构造函数结束时解开VAO时,你真的很幸运。由于在设置着色器时网格VAO仍然绑定,glVertexAttribPointer()glEnableVertexAttribArray()调用修改了网格VAO状态,从而产生了所需的结果。但如果您使用多个网格/着色器,这很可能会失败。

您需要在设置网格时设置顶点状态,同时绑定特定网格的VAO。以下调用都修改VAO状态,并且必须在绑定正确的VAO时进行:

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

在设置着色器程序时修改顶点设置状态在概念上也是有问题的。顶点设置状态不是着色器程序状态的一部分。