如何使用不同的 VAO、VBO 绘制 2 个或更多对象?
Posted
技术标签:
【中文标题】如何使用不同的 VAO、VBO 绘制 2 个或更多对象?【英文标题】:How to draw 2 or more objects with different VAO, VBO? 【发布时间】:2018-10-15 21:26:21 【问题描述】:我想画立方体和球体,但 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;
Main(我在代码中删除了立方体坐标,因为它太长了):
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;
【问题讨论】:
我对球体坐标有疑问,但不适用于这个问题。感谢@derhass 的帮助,如果我不创建额外的缓冲区,它真的可以工作! 【参考方案1】:您的 sphere
函数在内部创建一个新的 GL 缓冲区对象并返回其名称,因此:
GLuint sphereVBO = sphere(1, 30, 30);
您现在拥有包含该缓冲区名称的 sphereVBO
。
glGenVertexArrays(1, &VAO2); glGenBuffers(1, &sphereVBO);
但是现在,您创建了一个新的缓冲区对象,并用新名称覆盖了sphereVBO
。结果,您试图从一个空的缓冲区对象中进行绘制(没有调用 glBufferData
来实际为其创建数据存储),并且您完全失去了对球体数据的原始 VBO 的跟踪。
【讨论】:
我编辑代码删除glGenBuffers
。我在 glBindBuffer
中调用方法 sphere(1, 30, 30)
,但效果不佳。 :(以上是关于如何使用不同的 VAO、VBO 绘制 2 个或更多对象?的主要内容,如果未能解决你的问题,请参考以下文章