绑定GL_ELEMENT_ARRAY_BUFFER VBO并启用GL_NORMAL_ARRAY后OpenGL程序异常求助
基于GLEW和GLUT开发的OpenGL程序编译正常,但运行时黑屏并自行退出,结合提供的代码,问题主要集中在以下几点:
GLEW初始化错误处理不当
代码仅在glewInit()返回GLEW_OK时进入glutMainLoop(),若初始化失败(如上下文未正确绑定、版本不兼容),程序会直接退出,表现为黑屏一闪而过。
修复:添加错误提示逻辑,确保能定位初始化失败原因,同时调整主循环执行逻辑:GLenum err = glewInit(); if (err != GLEW_OK) { cerr << "GLEW初始化失败: " << glewGetErrorString(err) << endl; } glutMainLoop(); // 无论GLEW是否初始化成功,都进入主循环(若不依赖GLEW扩展功能)错误启用GL_NORMAL_ARRAY且无有效法线数据
代码启用了GL_NORMAL_ARRAY客户端状态,但仅上传了顶点数据到VBO,glNormalPointer指定类型为GL_UNSIGNED_BYTE,却指向float类型的顶点数据,导致OpenGL读取错误的法线信息。同时默认GL_LIGHTING处于开启状态,错误的法线会引发光照计算异常,物体无法被照亮。
修复:根据需求选择以下方案:// 方案1:禁用光照(适合简单纯色绘制) glDisable(GL_LIGHTING); // 移除glEnableClientState(GL_NORMAL_ARRAY);和glNormalPointer(...)相关代码 // 方案2:添加合法线数据 GLfloat normals[] = {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f}; // 将顶点和法线数据合并到同一个VBO glBufferData(GL_ARRAY_BUFFER, sizeof(trianglevertices) + sizeof(normals), nullptr, GL_STATIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(trianglevertices), trianglevertices); glBufferSubData(GL_ARRAY_BUFFER, sizeof(trianglevertices), sizeof(normals), normals); // 正确设置指针 glVertexPointer(3, GL_FLOAT, 0, (void*)0); glNormalPointer(GL_FLOAT, 0, (void*)sizeof(trianglevertices));每次绘制重复创建/删除VBO
triangle()函数在每次display()调用时都执行VBO创建、数据上传、绘制后立即删除的操作,不仅效率极低,还可能引发OpenGL状态混乱。
修复:将VBO的创建与数据上传移至初始化函数,仅执行一次;绘制时仅绑定VBO并执行绘制命令,程序退出时再删除VBO:GLuint VBOid, VBOindex; // 全局或静态变量 void init() { // ... 其他初始化逻辑 ... GLfloat trianglevertices[] = {0.0f, .75f, 0.0f, -0.75f, 0.0f, 0.0f, 0.75f, 0.0f, 0.0f, -0.75f, -0.75f, 0.0f, 0.0f, 0.0f, 0.0f,0.75f, -0.75f, 0.0f}; GLubyte indices[] = {0,1,2,3,4,5}; glGenBuffers(1, &VBOid); glBindBuffer(GL_ARRAY_BUFFER, VBOid); glBufferData(GL_ARRAY_BUFFER, sizeof(trianglevertices), trianglevertices, GL_STATIC_DRAW); glGenBuffers(1, &VBOindex); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBOindex); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); } void triangle() { glBindBuffer(GL_ARRAY_BUFFER, VBOid); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBOindex); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, 0); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); glDisableClientState(GL_VERTEX_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } // 注册程序退出清理函数 void cleanup() { glDeleteBuffers(1, &VBOid); glDeleteBuffers(1, &VBOindex); }在
main()中添加glutCloseFunc(cleanup);注册清理函数。缺少基础矩阵配置
固定管线模式下,未明确设置投影与模型视图矩阵可能导致显示异常,同时glColor4f的效果也会受光照状态影响。
修复:在init()函数中添加矩阵与渲染状态配置:void init() { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 设置清屏颜色 glEnable(GL_COLOR_MATERIAL); // 让glColor4f生效(光照开启时) glDisable(GL_LIGHTING); // 关闭光照,简化绘制逻辑 // 设置正交投影矩阵 glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); // 重置模型视图矩阵 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); }在
main()中glutCreateWindow()后调用init()。
内容的提问来源于stack exchange,提问作者onesrjd

