无法使用 VAO 和 EBO (openGL) 绘制多个对象
Posted
技术标签:
【中文标题】无法使用 VAO 和 EBO (openGL) 绘制多个对象【英文标题】:Unable to draw multiple objects using VAOs and EBOs (openGL) 【发布时间】:2020-02-17 18:42:37 【问题描述】:我正在尝试使用顶点数组对象和元素缓冲区对象。我设法使用带有 EBO 边界的单个 VAO 在屏幕上绘制字母“H”,因为我的所有顶点和索引都在一个数组中。虽然我想将每个矩形分割成不同的对象并赋予它们不同的颜色,但只有其中一个在屏幕上绘制。
代码如下:
#include <glew.h>
#include <glfw3.h>
#include <iostream>
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"\n"
"gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"\0";
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"\n"
"FragColor = vec4(0.2f, 0.6f, 0.7f, 1.0f);\n"
"\0";
const char* fragmentShaderSource2 = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"\n"
"FragColor = vec4(0.7f, 0.4f, 0.3f, 1.0f);\n"
"\0";
const char* fragmentShaderSource3 = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"\n"
"FragColor = vec4(0.1f, 0.2f, 0.6f, 1.0f);\n"
"\0";
int main(void)
GLFWwindow* window;
glewInit();
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
glfwTerminate();
return -1;
/* Make the window's context current */
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK)
std::cout << "Error!" << std::endl;
float vertices[] =
0.2f, 0.7f, 0.0f,
0.3f, 0.7f, 0.0f,
0.3f, 0.2f, 0.0f,
0.2f, 0.2f, 0.0f
;
float vertices2[] =
0.6f, 0.7f, 0.0f,
0.7f, 0.7f, 0.0f,
0.7f, 0.2f, 0.0f,
0.6f, 0.2f, 0.0f
;
float vertices3[] =
0.3f, 0.4f, 0.0f,
0.3f, 0.5f, 0.0f,
0.6f, 0.5f, 0.0f,
0.6f, 0.4f, 0.0f
;
unsigned int indices[] =
1, 0, 2,
2, 3, 0
;
unsigned int indices2[] =
5, 4, 6,
6, 7, 4
;
unsigned int indices3[] =
8, 9, 11,
11, 10, 9
;
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
unsigned int fragmentShader2 = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader2, 1, &fragmentShaderSource2, NULL);
glCompileShader(fragmentShader2);
unsigned int fragmentShader3 = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader3, 1, &fragmentShaderSource3, NULL);
glCompileShader(fragmentShader3);
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
unsigned int shaderProgram2;
shaderProgram2 = glCreateProgram();
unsigned int shaderProgram3;
shaderProgram3 = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glAttachShader(shaderProgram2, fragmentShader2);
glAttachShader(shaderProgram2, vertexShader);
glLinkProgram(shaderProgram2);
glAttachShader(shaderProgram3, fragmentShader3);
glAttachShader(shaderProgram3, vertexShader);
glLinkProgram(shaderProgram3);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success)
glGetShaderInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glDeleteShader(fragmentShader2);
glDeleteShader(fragmentShader3);
unsigned int VBOs[3], VAOs[3], EBOs[3];
glGenVertexArrays(3, VAOs);
glGenBuffers(3, VBOs);
glGenBuffers(3, EBOs);
glBindVertexArray(VAOs[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(VAOs[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices2), vertices2, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2), indices2, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(VAOs[2]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices3), vertices3, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices3), indices3, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAOs[0]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glUseProgram(shaderProgram2);
glBindVertexArray(VAOs[1]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glUseProgram(shaderProgram3);
glBindVertexArray(VAOs[2]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
glDeleteVertexArrays(3, VAOs);
glDeleteBuffers(3, VBOs);
glDeleteBuffers(3, EBOs);
glfwTerminate();
return 0;
【问题讨论】:
【参考方案1】:你会在这里:
float vertices2[] = 0.6f, 0.7f, 0.0f, 0.7f, 0.7f, 0.0f, 0.7f, 0.2f, 0.0f, 0.6f, 0.2f, 0.0f ;
与:
unsigned int indices2[] = 5, 4, 6, 6, 7, 4 ;
这没有意义。您只需将 4 个顶点复制到 VBO[1]
,并将属性指针设置为该缓冲区中的偏移量 0,因此唯一有效的索引是 0
、1
、2
和 3
。
您的索引被设置为好像所有顶点都像以前一样在一个大数组中,实际上,这将是一个更好的策略:保留一个大顶点数组、一个大元素索引数组和一个 VAO,并且只需通过更改 glDrawElements()
调用中的 indices
参数来绘制该数组的各个部分,如下所示:
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // first 6 indices
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)(6*sizeof(GLuint))); // second 6 indices
// ...
也不是说在这里使用 3 个不同的着色器效率很低。如果您只是将颜色添加为另一个属性,并且对所有内容使用单个绘制调用(意味着单个着色器、单个 VAO),那将是最好的选择。
【讨论】:
天哪!我不敢相信我错过了这么简单的事情。当然它没有工作。谢谢!我知道这也不是很有效。只是想尝试一下。以上是关于无法使用 VAO 和 EBO (openGL) 绘制多个对象的主要内容,如果未能解决你的问题,请参考以下文章
Android OpenGL ES 学习 – 使用 VBOVAO 和 EBO/IBO 优化程序
OpenGL入门之渲染管线pipeline,VAOVBO和EBO