在OpenGL4中绘制两个对象?

时间:2014-09-21 16:50:12

标签: c++ opengl

我试图在OpenGL中绘制2个对象。窗口/视口是(0,0,950,1050)。我不确定这是正确的做法,但我是这么认为的。我认为这个想法是为每个对象创建一个VBO / VAO,绑定它,设置数据,并为每个对象重复该操作。

然后在绘制对象时:

  • 设置着色器
  • 使用其vbo(比如vbo1)
  • 绑定我们想要绘制的第一个对象的数据
  • 进行绘图调用
  • 使用其vbo(比如vbo2)
  • 绑定我们想要绘制的下一个对象的数据
  • 进行绘图调用
  • ...

当我这样做时,我只获得在屏幕上绘制的第二个对象的点,但是使用第一个对象的颜色(它是蓝色而不是红色)。

我的错误必须对那里的任何专家都很明显。我错过了什么?

// BLUE -----------------------------------
GLuint vbo1, vao1;
glGenBuffers(1, &vbo1);
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
float arr1[] = { 10, 10, 10, 110, 110, 110, 110, 10 };
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, arr1, GL_STATIC_DRAW);

glGenVertexArrays(1, &vao1);
glBindVertexArray(vao1);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);

// RED  -----------------------------------
GLuint vbo2, vao2;
glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
float arr2[] = { 400, 400, 400, 800, 800, 800, 800, 400 };
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, arr2, GL_STATIC_DRAW);

glGenVertexArrays(1, &vao2);
glBindVertexArray(vao2);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);

while (!glfwWindowShouldClose(window))
{
    glClearColor(1, 1, 1, 0.1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(pointShader);

    GLint loc;
    loc  = glGetUniformLocation(pointShader, "pointColor");

    // it draws this one but with the color blue!
    glBindBuffer(GL_ARRAY_BUFFER, vbo2);
    float ptColor2[3] = { 1, 0, 0 };
    glUniform3fv(loc, 1, ptColor2);
    glDrawArrays(GL_POINTS, 0, 4);

    // it doesn't draw this one???
    glBindBuffer(GL_ARRAY_BUFFER, vbo1);
    float ptColor1[3] = { 0, 0, 1 };
    glUniform3fv(loc, 1, ptColor1);
    glDrawArrays(GL_POINTS, 0, 4);

    glfwSwapBuffers(window);
    glfwWaitEvents();
}

enter image description here

编辑2工作代码

非常感谢Reto Koradi和Datenwolf。结合答案,有助于得到正确的答案。遗憾的是,书中没有正确解释这些事情。希望这篇文章能够帮助其他初学者(对不起,如果结果有点误导,我在询问问题时和我得到答案时交换颜色)。

// RED -----------------------------------
GLuint vbo1, vao1;

glGenVertexArrays(1, &vao1);
glBindVertexArray(vao1);

glGenBuffers(1, &vbo1);
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
float arr1[] = { 10, 10, 10, 110, 110, 110, 110, 10 };
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, arr1, GL_STATIC_DRAW);

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);

// BLUE  -----------------------------------
GLuint vbo2, vao2;

glGenVertexArrays(1, &vao2);
glBindVertexArray(vao2);

glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
float arr2[] = { 400, 400, 400, 800, 800, 800, 800, 400 };
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, arr2, GL_STATIC_DRAW);

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);

while (!glfwWindowShouldClose(window))
{
    float ratio;
    int width, height;
    glfwGetFramebufferSize(window, &width, &height);

    glClearColor(1, 1, 1, 0.1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(pointShader);

    GLint loc;
    loc  = glGetUniformLocation(pointShader, "pointColor");

    // red
    glBindVertexArray(vao1);
    float ptColor1[3] = { 1, 0, 0 };
    glUniform3fv(loc, 1, ptColor1);
    glDrawArrays(GL_POINTS, 0, 4);

    // blue
    glBindVertexArray(vao2);
    float ptColor2[3] = { 0, 0, 1 };
    glUniform3fv(loc, 1, ptColor2);
    glDrawArrays(GL_POINTS, 0, 4);

    glfwSwapBuffers(window);
    glfwWaitEvents();
}

enter image description here

编辑3

请注意,虽然VAO / VBO订单声明的第一个代码片段的顺序也可以。所以上面的版本和下面的版本都是有效的:

// RED -----------------------------------
GLuint vbo1, vao1;

glGenBuffers(1, &vbo1);
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
float arr1[] = { 10, 10, 10, 110, 110, 110, 110, 10 };
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, arr1, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao1);
glBindVertexArray(vao1);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);

// BLUE  -----------------------------------
GLuint vbo2, vao2;

glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
float arr2[] = { 400, 400, 400, 800, 800, 800, 800, 400 };
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, arr2, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao2);
glBindVertexArray(vao2);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);

代码中唯一缺少的是glBindVertexArray

2 个答案:

答案 0 :(得分:2)

在指定顶点属性数据位置(glVertexAttribPointer)之前,必须创建并绑定顶点数组对象。 VAO类型在进行这些调用时获取属于当前绑定的VBO的数据的所有权。

(EDIT在打字时意外提交)

假设您有一个核心配置文件上下文,当您尝试创建第一个缓冲区对象时,尚未将VAO绑定到它,因此整个BO的创建失败。因此,当您尝试绘制它时,根本没有绘制任何内容。但是你看到的是你想要绑定到第二个VAO的BO,但是由于你的操作顺序错误,它最终会出现在第一个VAO中。

答案 1 :(得分:2)

问题出在您的绘制循环中,您可以在其中调用:

glBindBuffer(GL_ARRAY_BUFFER, vbo2);

进行绘制调用时,当前绑定的GL_ARRAY_BUFFER无关紧要。当您调用glVertexAttribPointer()时,需要绑定正确的缓冲区,这是您在设置代码中正确执行的操作。

VAO跟踪所有顶点设置状态。因此,在每次绘制调用之前,您需要通过调用glBindVertexArray()来绑定相应的VAO,而不是在发布的代码中调用glBindBuffer()

glBindVertexArray(vao2);
glUniform3fv(...);
glDrawArrays(...);

glBindVertexArray(vao1);
glUniform3fv(...);
glDrawArrays(...);