glDrawElements无输出排查:OpenGL绘制正方形窗口空白问题
问题:OpenGL程序仅显示空白窗口,无法渲染正方形
我编写了如下简单代码:
#include <iostream> #include <memory> #include <glad/glad.h> #include <GLFW/glfw3.h> #include <glm/glm.hpp> #include <test/main/shader.hpp> class Foo { public: void OnAttach() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); window_ = glfwCreateWindow(960, 540, "test", nullptr, nullptr); if (window_ == nullptr) { std::cerr << "failed to create GLFW window\n"; } glfwMakeContextCurrent(window_); glfwSetFramebufferSizeCallback(window_, [](GLFWwindow *_, int width, int height) { glViewport(0, 0, width, height); }); if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) { std::cerr << "failed to initialize GLAD\n"; } glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); shader_ = std::make_shared<Shader>("assets/GLSL/test.glsl"); glGenVertexArrays(1, &quad_va_); glBindVertexArray(quad_va_); float vertices[] = { -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.5f, 0.5f, 0.0f, -0.5f, 0.5f, 0.0f }; glGenBuffers(1, &quad_vb_); glBindBuffer(GL_ARRAY_BUFFER, quad_vb_); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, nullptr); glEnableVertexAttribArray(0); uint32_t indices[] = {0, 1, 2, 2, 3, 0}; glGenBuffers(1, &quad_ib_); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_ib_); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); } void OnUpdate() { glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); shader_->Bind(); shader_->SetVec3("u_color", square_color_); glBindVertexArray(quad_va_); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); } GLFWwindow *GetWindow() const { return window_; } private: GLFWwindow *window_; std::shared_ptr<Shader> shader_; uint32_t quad_va_, quad_vb_, quad_ib_; glm::vec4 square_color_ = {0.8f, 0.2f, 0.3f, 1.0f}; }; void Run(Foo *foo) { foo->OnAttach(); while (!glfwWindowShouldClose(foo->GetWindow())) { foo->OnUpdate(); glfwSwapBuffers(foo->GetWindow()); glfwPollEvents(); } } int main() { Run(new Foo); }
对应的着色器代码如下:
#type vertex #version 330 core layout(location = 0) in vec3 a_pos; uniform mat4 u_view_projection; void main() { gl_Position = vec4(a_pos, 1.0); } #type fragment #version 330 core out vec4 color; uniform vec4 u_color; void main() { color = u_color; }
其中Shader类负责解析包含顶点和片段部分的着色器文件,并在帧循环中设置uniform变量。运行程序后仅看到空白窗口,未显示预期的正方形,但所有配置步骤看似正确。请问问题出在哪里?
补充说明:为完整起见,以下是Shader类的代码:
头文件:
#ifndef TEST_SHADER_HPP #define TEST_SHADER_HPP #include <string> #include <glm/glm.hpp> class Shader { public: explicit Shader(const std::string& filepath); void Bind() const; void SetInt(const std::string& name, int value) const; void SetFloat(const std::string& name, float value) const; void SetVec3(const std::string& name, const glm::vec3& vec) const; void SetVec4(const std::string& name, const glm::vec4& vec) const; void SetMat4(const std::string& name, const glm::mat4& mat) const; private: static void CheckCompileErrors(uint32_t shader_id, const std::string& type, const std::string& filepath); uint32_t id_; }; #endif //TEST_SHADER_HP
源文件:
#include <test/main/shader.hpp> #include <iostream> #include <fstream> #include <sstream> #include <glad/glad.h> void Shader::CheckCompileErrors(uint32_t shader_id, const std::string& type, const std::string& filepath) { int success; char infoLog[1024]; if (type != "PROGRAM") { glGetShaderiv(shader_id, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(shader_id, 1024, nullptr, infoLog); std::cout << "ERROR::SHADER::COMPILATION_ERROR of type: " << type << "\n" << infoLog << "filepath: " << filepath; } } else { glGetProgramiv(shader_id, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shader_id, 1024, nullptr, infoLog); std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "filepath: " << filepath; } } } Shader::Shader(const std::string& filepath) { // 1. divide vertex and fragment part enum class ShaderType { NONE = -1, VERTEX = 0, FRAGMENT = 1 }; std::ifstream stream(filepath); std::string line; std::stringstream ss[2]; ShaderType type = ShaderType::NONE; while (getline(stream, line)) { if (line.find("#type") != std::string::npos) { if (line.find("vertex") != std::string::npos) { type = ShaderType::VERTEX; } else if (line.find("fragment") != std::string::npos) { type = ShaderType::FRAGMENT; } else { std::cout << "Unknown shader: " << line << '\n'; } } else { if (type == ShaderType::NONE) { std::cout << "No shader defined" << '\n'; } else { ss[(int) type] << line << '\n'; } } } std::string vertex_code = ss[(int) ShaderType::VERTEX].str(); std::string fragment_code = ss[(int) ShaderType::FRAGMENT].str(); // 2. convert, compile and link sources to shader program // 2.1 convert string to c str const char *vertex_str = vertex_code.c_str(); const char *fragment_str = fragment_code.c_str(); // 2.2.1 vertex shader uint32_t vertex_id = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex_id, 1, &vertex_str, nullptr); glCompileShader(vertex_id); CheckCompileErrors(vertex_id, "VERTEX", filepath); // 2.2.2 fragment shader uint32_t fragment_id = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment_id, 1, &fragment_str, nullptr); glCompileShader(fragment_id); CheckCompileErrors(fragment_id, "FRAGMENT", filepath); // 2.3 shader program id_ = glCreateProgram(); glAttachShader(id_, vertex_id); glAttachShader(id_, fragment_id); glLinkProgram(id_); CheckCompileErrors(id_, "PROGRAM", filepath); // 2.4 delete the shaders as they're linked into program and no longer necessary glDeleteShader(vertex_id); glDeleteShader(fragment_id); } void Shader::Bind() const { glUseProgram(id_); } void Shader::SetInt(const std::string& name, int value) const { glUniform1i(glGetUniformLocation(id_, name.c_str()), value); } void Shader::SetFloat(const std::string& name, float value) const { glUniform1f(glGetUniformLocation(id_, name.c_str()), value); } void Shader::SetVec4(const std::string& name, const glm::vec4& vec) const { glUniform4f(glGetUniformLocation(id_, name.c_str()), vec.x, vec.y, vec.z, vec.w); } void Shader::SetVec3(const std::string& name, const glm::vec3& vec) const { glUniform3f(glGetUniformLocation(id_, name.c_str()), vec.x, vec.y, vec.z); } void Shader::SetMat4(const std::string& name, const glm::mat4& mat) const { glUniformMatrix4fv(glGetUniformLocation(id_, name.c_str()), 1, GL_FALSE, &mat[0][0]); }
问题分析与解决
导致空白窗口的核心问题有两处:
Uniform变量类型不匹配
片段着色器中u_color是vec4类型,但主程序调用SetVec3传递值。SetVec3只会设置x、y、z分量,w分量默认被设为0.0,导致片段完全透明,自然无法看到正方形。
解决:将shader_->SetVec3("u_color", square_color_);改为shader_->SetVec4("u_color", square_color_);,完整传递四个分量。未使用的Uniform变量引发链接问题
顶点着色器声明了uniform mat4 u_view_projection但未使用,也没有在程序中设置值。OpenGL核心模式下,这种未使用的活动Uniform会导致链接异常,程序行为不稳定。
解决:要么删除顶点着色器中该变量,要么在OnAttach中添加代码设置单位矩阵:shader_->Bind(); shader_->SetMat4("u_view_projection", glm::mat4(1.0f));
另外还有一个潜在风险:GLFW窗口创建失败后没有终止程序,后续代码可能访问空指针window_引发崩溃,建议在窗口创建失败后添加glfwTerminate(); return;退出流程。
内容的提问来源于stack exchange,提问作者milanHrabos
相关产品推荐
相关产品推荐

