如何使用不同的VAO,VBO绘制2个或更多对象?

时间:2018-10-15 21:26:22

标签: c++ opengl glfw glm-math

我想绘制立方体和球体,但是openGl仅绘制立方体。我制作了2个VAO:第一个VAO包含VBO(带有坐标立方体),其他VAO包含坐标球。如果我只想绘制球体,那么它也不起作用。也许是由于VBO绑定不正确而发生的...但是我不完全了解如何处理它。

下面的代码(构成范围):

GLuint sphere(float radius, int slices, int stacks) {
GLuint vbo;
int n = 2 * (slices + 1) * stacks;
int i = 0;
vec3 *points = new vec3[n];

for (float theta = -M_PI / 2; theta < M_PI / 2 - 0.0001; theta += M_PI / stacks) {
    for (float phi = -M_PI; phi <= M_PI + 0.0001; phi += 2 * M_PI / slices) {
        points[i++] = vec3(cos(theta) * sin(phi), -sin(theta), cos(theta) * cos(phi));
        points[i++] = vec3(cos(theta + M_PI / stacks) * sin(phi), -sin(theta + M_PI / stacks), cos(theta + M_PI / stacks) * cos(phi));
    }
}

glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

return vbo;}

主要(我在代码中删除了立方体坐标,因为它太长了):

glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Laba5", nullptr, nullptr);
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
glewExperimental = GL_TRUE;
glewInit();

glViewport(0, 0, WIDTH, HEIGHT);
glEnable(GL_DEPTH_TEST);

Shader ourShader("shader.vs", "shader.frag");
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0); // Unbind VAO
//-----------------------------------------------------------2
GLuint VAO2;
glGenVertexArrays(1, &VAO2);
glBindVertexArray(VAO2);
glBindBuffer(GL_ARRAY_BUFFER, sphere(1, 30, 30));
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindVertexArray(0); // Unbind VAO

while (!glfwWindowShouldClose(window))
{

    // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
    glfwPollEvents();

    glClearColor(0.32f, 0.31f, 0.30f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    ourShader.Use();

    mat4 view = mat4(1.0);
    mat4 projection = mat4(1.0);
    view = translate(view, vec3(1.0f, 1.0f, -4.8f));
    projection = perspective(45.0f, (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f);
    GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
    GLint viewLoc = glGetUniformLocation(ourShader.Program, "view");
    GLint projLoc = glGetUniformLocation(ourShader.Program, "projection");

    glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
    glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

    if (lbutton_down)
    {
        double cur_mx, cur_my;
        glfwGetCursorPos(window, &cur_mx, &cur_my);
        if (cur_mx != last_mx || cur_my != last_my)
        {
            vec3 va = get_arcball_vector(last_mx, last_my);
            vec3 vb = get_arcball_vector(cur_mx, cur_my);
            float angle = acos(min(1.0f, dot(va, vb)));
            vec3 axis_in_camera_coord = cross(va, vb);
            mat3 camera2object = inverse(model);
            vec3 axis_in_object_coord = camera2object * axis_in_camera_coord;
            model = rotate(model, degrees(angle)*0.05f, axis_in_object_coord);
            last_mx = cur_mx;
            last_my = cur_my;
        }
    }

    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);

    glBindVertexArray(VAO2);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 2 * 31 * 30);
    glBindVertexArray(0);

    glfwSwapBuffers(window);
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteVertexArrays(1, &VAO2);
glfwTerminate();
return 0;

1 个答案:

答案 0 :(得分:0)

您的sphere函数在内部创建一个新的GL缓冲区对象并返回其名称,因此:

GLuint sphereVBO = sphere(1, 30, 30);

您现在有sphereVBO包含该缓冲区的名称。

glGenVertexArrays(1, &VAO2);
glGenBuffers(1, &sphereVBO);

但是现在,您创建了一个新的缓冲区对象,并使用新名称覆盖了sphereVBO。结果,您试图从一个空的缓冲区对象中进行绘制(没有调用glBufferData来为其实际创建数据存储),并且您完全失去了使用球体数据跟踪原始VBO的信息。 / p>