我正在尝试回到 OpenGL,自从我上次使用它以来,很多事情都发生了变化。不过,我尝试编写一个小型 3D 程序。现在程序应该显示两个基本的旋转立方体。
我的问题是,该程序只显示每个立方体一个三角形。看起来从VBO 中只读取了一个三角形。 我的第一次调试是围绕数据本身进行的,也许我弄乱了三角形或索引,但对我来说这看起来不错(还尝试了其他几个 OpenGL 教程中的顶点和索引列表)。 我还打乱了OpenGL函数的顺序,也许它们的顺序有问题。 但没有任何帮助,输出仍然只是每个立方体一个三角形。
该程序当前由一个“引擎”组成,它处理窗口和基本 OpenGL 设置以及主渲染循环:
int my3DEngine::Run() {
int return_value = ENGINE_OK;
// Camera matrix
glm::mat4 View = glm::lookAt(
glm::vec3(4, 3, 3), // Camera is at (4,3,3), in World Space
glm::vec3(0, 0, 0), // and looks at the origin
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);
do {
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// glClearColor(m_color_R, m_color_G, m_color_B, m_color_A);
//draw object list
for (std::size_t i = 0; i < m_objects.size(); i++) {
m_objects[i]->update();
m_objects[i]->draw(m_projection, View);
}
// Swap buffers
glfwSwapBuffers(m_window);
glfwPollEvents();
} // Check if the ESC key was pressed or the window was closed
while (!glfwWindowShouldClose(m_window));
return return_value;
}
正如你所看到的,还有对象。该对象初始化如下:
...
float vertices[] = {
//positions //colors
-1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, // 0. left bottom back
1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // 1. right bottom back
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, // 2. right top back
-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, // 3. left top back
-1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, // 4. left bottom front
1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 5. right bottom front
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // 6. right top front
-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f // 7. left top front
};
// Vertex index list
unsigned int indices[] = {
0, 1, 2, // triangle 1 (back face)
2, 3, 0, // triangle 2 (back face)
4, 5, 6, // triangle 3 (front face)
6, 7, 4, // triangle 4 (front face)
3, 2, 6, // triangle 5 (top face)
6, 7, 3, // triangle 6 (top face)
1, 0, 4, // triangle 7 (bottom face)
4, 5, 1, // triangle 8 (bottom face)
0, 3, 7, // triangle 9 (left face)
7, 4, 0, // triangle 10 (left face)
1, 5, 6, // triangle 11 (right face)
6, 2, 1 // triangle 12 (right face)
};
if (engine->Init() == ENGINE_OK) {
// Open a window and create its OpenGL context
if (engine->CreateMainWindow(1024, 768, "test", "data/icon/test.png", true, false) == ENGINE_OK) {
obj->addShader(engine->LoadShaders("shaders/vertex.sh", "shaders/fragment_red.sh"));
obj->addVertexData(vertices, g_vertex_indices_data, sizeof(vertices), sizeof(indices), sizeof(vertices)/sizeof(GLfloat)/6, sizeof(indices)/sizeof(GLuint), GL_TRIANGLES);
obj->setRotationSpeed(glm::vec3(0.002, 0.002f, 0.002f));
obj->setPos(glm::vec3(0.0f,0.0f,-2.1f));
obj_2->addShader(engine->LoadShaders("shaders/vertex.sh", "shaders/fragment.sh"));
obj_2->addVertexData(vertices, g_vertex_indices_data, sizeof(vertices), sizeof(indices), sizeof(vertices) / sizeof(GLfloat) / 6, sizeof(indices) / sizeof(GLuint), GL_TRIANGLES);
obj_2->setRotationSpeed(glm::vec3(-0.002, -0.002f, -0.002f));
engine->addObject(obj);
engine->addObject(obj_2);
engine->setBackgrundColor(0.0f, 0.0f, 0.4f, 0.0f);
engine->Run();
}
else {
return_value = ENGINE_FATAL_ERROR;
std::cerr << "Unable to create the window!" << std::endl;
}
}
else {
return_value = ENGINE_FATAL_ERROR;
std::cerr << "Unable to initialize the engine!" << std::endl;
}
我认为最有趣的函数是对象顶点设置函数及其绘制函数:
void my3DEngineObject::addVertexData(const GLfloat vertex_data[], const GLuint vertex_indices[], const size_t vertex_data_size, const size_t vertex_indices_size, int nr_vertices, int nr_indices, GLenum mode) {
m_vertex_data_size = vertex_data_size;
m_vertex_index_size = vertex_indices_size;
m_vertex_data = new GLfloat[m_vertex_data_size];
m_vertex_index_data = new GLuint[vertex_indices_size];
memcpy(m_vertex_data, vertex_data, m_vertex_data_size);
memcpy(m_vertex_index_data, vertex_indices, m_vertex_index_size);
m_nr_vertices = nr_vertices;
m_nr_indices = nr_indices;
m_mode = mode;
glGenVertexArrays(1, &m_vertexArray);
glGenBuffers(1, &m_vertexbuffer);
glGenBuffers(1, &m_indexbuffer);
glBindVertexArray(m_vertexArray);
// bind and fill the vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, m_vertex_data_size, m_vertex_data, GL_STATIC_DRAW);
//bind and fill the indices buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_vertex_index_size, m_vertex_index_data, GL_STATIC_DRAW);
}
void my3DEngineObject::addShader(GLuint id) {
m_shaderID = id;
m_shader_MVP_handle = glGetUniformLocation(m_shaderID, "MVP");
}
void my3DEngineObject::update() {
m_angle_radians += m_rot_speed;
m_pos += m_trans_speed;
}
void my3DEngineObject::draw(glm::mat4 projection, glm::mat4 view) {
//rotate around its own center
//m_rotationMatrix_X = glm::rotate(glm::mat4(1.0f), glm::radians(m_rot_speed.x), glm::vec3(1.0f, 0.0f, 0.0f));
//m_rotationMatrix_Y = glm::rotate(glm::mat4(1.0f), glm::radians(m_rot_speed.y), glm::vec3(0.0f, 1.0f, 0.0f));
//m_rotationMatrix_Z = glm::rotate(glm::mat4(1.0f), glm::radians(m_rot_speed.z), glm::vec3(0.0f, 0.0f, 1.0f));
m_modelMatrix = m_identity_matrix;
m_translationMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(m_pos.x, m_pos.y, m_pos.z)); //position the object in world space
m_modelMatrix = m_modelMatrix * m_translationMatrix;
m_rotationMatrix_X = glm::rotate(glm::mat4(1.0f), m_angle_radians.x, glm::vec3(1.0f, 0.0f, 0.0f)); //rotate the object around its centerpoint
m_rotationMatrix_Y = glm::rotate(glm::mat4(1.0f), m_angle_radians.y, glm::vec3(0.0f, 1.0f, 0.0f));
m_rotationMatrix_Z = glm::rotate(glm::mat4(1.0f), m_angle_radians.z, glm::vec3(0.0f, 0.0f, 1.0f));
m_modelMatrix = m_modelMatrix * m_rotationMatrix_X * m_rotationMatrix_Y * m_rotationMatrix_Z;
//set modelview projection matrix
m_MVP = projection * view * m_modelMatrix;
drawObject();
}
void my3DEngineObject::drawObject() {
if (m_shaderID != ENGINE_FATAL_ERROR) {
glUseProgram(m_shaderID);
glUniformMatrix4fv(m_shader_MVP_handle, 1, GL_FALSE, &m_MVP[0][0]);
}
glBindVertexArray(m_vertexArray);
// position attribute
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
// color attribute
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glDrawElements(GL_TRIANGLES, m_nr_indices, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
glBindVertexArray(0);
}
但是,当我将测试数据直接放入 addVertexData 函数时,它就可以工作了。
void my3DEngineObject::addVertexData(const GLfloat vertex_data[], const GLuint vertex_indices[], const size_t vertex_data_size, const size_t vertex_indices_size, int nr_vertices, int nr_indices, GLenum mode) {
GLfloat vertices[] = {
//positions //colors
-1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, // 0. left bottom back
1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // 1. right bottom back
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, // 2. right top back
-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, // 3. left top back
-1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, // 4. left bottom front
1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 5. right bottom front
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // 6. right top front
-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f // 7. left top front
};
// Vertex index list
GLuint indices[] = {
0, 1, 2, // triangle 1 (back face)
2, 3, 0, // triangle 2 (back face)
4, 5, 6, // triangle 3 (front face)
6, 7, 4, // triangle 4 (front face)
3, 2, 6, // triangle 5 (top face)
6, 7, 3, // triangle 6 (top face)
1, 0, 4, // triangle 7 (bottom face)
4, 5, 1, // triangle 8 (bottom face)
0, 3, 7, // triangle 9 (left face)
7, 4, 0, // triangle 10 (left face)
1, 5, 6, // triangle 11 (right face)
6, 2, 1 // triangle 12 (right face)
};
m_nr_vertices = 8;
m_nr_indices = 36;
m_mode = mode;
glGenVertexArrays(1, &m_vertexArray);
glGenBuffers(1, &m_vertexbuffer);
glGenBuffers(1, &m_indexbuffer);
glBindVertexArray(m_vertexArray);
// bind and fill the vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//bind and fill the indices buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
}
所以我怀疑数据在传递给函数的过程中丢失了。我不认为它是 memcopy,因为当我直接使用来自输入参数
const GLfloat vertex_data[]
和 const GLuint vertex_indices[]
的数据时,它仍然不起作用。
我发现了我的问题,这只是我一直忽视的一个非常愚蠢的类型。为了进行测试,我必须使用对象,一个简单的三角形和立方体:
static const GLfloat g_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
static const GLuint g_vertex_indices_data[] = {
0,1,2
};
GLfloat vertices[] = {
//positions //colors
-1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, // 0. left bottom back
1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // 1. right bottom back
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, // 2. right top back
-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, // 3. left top back
-1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, // 4. left bottom front
1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 5. right bottom front
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // 6. right top front
-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f // 7. left top front
};
// Vertex index list
GLuint indices[] = {
0, 1, 2, // triangle 1 (back face)
2, 3, 0, // triangle 2 (back face)
4, 5, 6, // triangle 3 (front face)
6, 7, 4, // triangle 4 (front face)
3, 2, 6, // triangle 5 (top face)
6, 7, 3, // triangle 6 (top face)
1, 0, 4, // triangle 7 (bottom face)
4, 5, 1, // triangle 8 (bottom face)
0, 3, 7, // triangle 9 (left face)
7, 4, 0, // triangle 10 (left face)
1, 5, 6, // triangle 11 (right face)
6, 2, 1 // triangle 12 (right face)
};
当我将立方体的数据传递给 addVertexData 函数时,我意外地使用了单个三角形的索引:
obj->addVertexData(vertices, g_vertex_indices_data, sizeof(vertices), sizeof(indices), sizeof(vertices)/sizeof(GLfloat)/6, sizeof(indices)/sizeof(GLuint), GL_TRIANGLES);
现在效果很好...