使用VBO加载Wavefront对象绘制立方体无显示,求排查绑定问题
问题分析与修复方案
让我们一步步排查你遇到的问题,核心问题集中在绘制逻辑、参数设置和属性数据匹配上,具体如下:
1. 错误的绘制方式:立即模式与VBO不兼容
你用glBegin(GL_TRIANGLES)包裹glArrayElement的写法是OpenGL立即模式的用法,这种方式不会正确读取VBO中的数据——glArrayElement在立即模式下会从客户端内存的顶点数组读取,而非绑定的VBO。正确的VBO绘制应该直接使用glDrawElements,完全不需要glBegin/glEnd代码块。
2. glDrawElements参数错误
你注释里的glDrawElements(GL_TRIANGLES,3,GL_INT,0)有两个关键问题:
- 第二个参数是要绘制的索引总数,你的
element数组有36个元素(对应12个三角形),所以应该传36而非3。 - OpenGL规范推荐使用无符号整数作为索引类型,建议把
element数组改成unsigned int类型,同时参数传GL_UNSIGNED_INT(部分实现支持GL_INT,但无符号类型是标准用法)。
修正后的调用代码:
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
3. 顶点属性数据不匹配导致越界
你的顶点数组是24个float(8个顶点,每个3分量),但法线数组只有18个float(6个法线),颜色数组是36个float(12个颜色),而索引数组有36个元素。当使用glDrawElements时,每个索引值会同时从顶点、法线、颜色数组中取对应下标的元素——比如索引8会尝试读取法线数组的第8个元素,但你的法线数组只有6个,这会导致非法内存访问,不仅显示异常,甚至可能崩溃。
你需要调整法线和颜色数组的长度,确保覆盖所有索引的访问:
- 如果是每个顶点对应一个法线,法线数组应该是8×3=24个float,和顶点数组长度一致。
- 如果是每个面对应一个法线(立方体每个面一个方向),需要为每个面的6个索引重复对应的法线数据,比如每个面的6个索引都使用同一个法线,这样法线数组长度应为36×3=108个float。
- 颜色数组同理,要确保每个索引都能取到对应的颜色值。
4. 初始化代码的规范优化(非致命,但更清晰)
你的初始化代码同时绑定两个VBO目标后传数据,语法上没问题,但分开绑定更清晰,避免混淆:
static void init(void){ // ... 其他初始化代码(如清屏颜色、深度测试等) GLuint vbo_id, index_id; glGenBuffers(1, &vbo_id); glBindBuffer(GL_ARRAY_BUFFER, vbo_id); glBufferData(GL_ARRAY_BUFFER, sizeof(vbo), vbo, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); // 解绑数组缓冲区 glGenBuffers(1, &index_id); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_id); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element), element, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // 解绑索引缓冲区 // 注意:vbo_id和index_id需要定义为全局变量,否则display函数无法访问 }
5. 检查视锥体与矩阵设置
如果以上修复后仍看不到立方体,大概率是矩阵设置问题——你没有将立方体放在相机的可视范围内。在init或display函数中添加矩阵配置:
// 设置投影矩阵 glMatrixMode(GL_PROJECTION); glLoadIdentity(); // 假设窗口宽高比为width/height,近裁剪面0.1,远裁剪面100 gluPerspective(45.0f, (float)window_width/window_height, 0.1f, 100.0f); // 设置模型视图矩阵 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -5.0f); // 将立方体移到相机前方5个单位
修正后的display函数示例
static void display(void){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 别忘了清屏 glBindBuffer(GL_ARRAY_BUFFER, vbo_id); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_id); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); // 属性指针偏移计算是正确的,无需修改 glVertexPointer(3, GL_FLOAT, 0, 0); glNormalPointer(GL_FLOAT, 0, (void*)(24*sizeof(float))); glColorPointer(3, GL_FLOAT, 0, (void*)(42*sizeof(float))); // 直接用glDrawElements绘制,无需glBegin/glEnd glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glutSwapBuffers(); // 如果使用双缓冲,别忘了交换缓冲区 }
按照这些步骤修复后,你的立方体应该能正常显示了。
内容的提问来源于stack exchange,提问作者ShaoyuPei
相关产品推荐
相关产品推荐

