OpenGL+Shaders创建圆柱与平面时渲染失败求助
问题分析与修复方案
你的代码存在几个核心问题,导致添加平面后圆柱和平面都无法显示:
1. VBO/EBO数据被覆盖
你先后将cylinderVBO和planeVBO绑定到GL_ARRAY_BUFFER,但最后绑定的是planeVBO,后续调用glBufferData时,先传入圆柱数据再传入平面数据,这会导致平面数据覆盖到planeVBO中,而cylinderVBO根本没有写入数据。同理,EBO也被平面的索引覆盖,最终EBO里只有平面的6个索引,但你绘制时使用了60个索引,直接越界,自然无法渲染任何内容。
2. 平面索引编号错误
平面的索引用了14、15、16、17这类全局顶点编号,但平面的VBO是独立的,它的顶点是从0开始计数的,应该改成0、1、2、3这类本地索引。
3. 未为不同形状分配独立VAO
VAO的作用是存储顶点属性配置、绑定的VBO/EBO信息,不同形状哪怕数据结构相同,也应该使用独立VAO,否则切换绘制时会互相干扰。
4. 绘制逻辑未区分不同形状
draw()函数固定使用60个索引,只适用于圆柱,平面需要单独指定索引数量(6个)。
修改后的关键代码片段
1. 为圆柱和平面分别创建VAO、EBO
GLuint cylinderVBO, planeVBO, cylinderEBO, planeEBO, cylinderVAO, planeVAO; // 配置圆柱的VAO、VBO、EBO glGenVertexArrays(1, &cylinderVAO); glGenBuffers(1, &cylinderVBO); glGenBuffers(1, &cylinderEBO); glBindVertexArray(cylinderVAO); glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(cylinderVertices), cylinderVertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderEBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cylinderIndices), cylinderIndices, GL_STATIC_DRAW); // 设置顶点属性 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); glBindVertexArray(0); // 配置平面的VAO、VBO、EBO glGenVertexArrays(1, &planeVAO); glGenBuffers(1, &planeVBO); glGenBuffers(1, &planeEBO); glBindVertexArray(planeVAO); glBindBuffer(GL_ARRAY_BUFFER, planeVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeEBO); // 修正平面索引为本地编号 GLubyte planeIndices[] = { 0,2,1, 2,3,1 }; glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(planeIndices), planeIndices, GL_STATIC_DRAW); // 设置顶点属性(和圆柱结构一致) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); glBindVertexArray(0);
2. 修改主循环绘制逻辑,分别渲染圆柱和平面
// 主循环内的绘制部分 glUseProgram(shaderProgram); // 传递视图、投影矩阵(只需要传一次) glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(viewMatrix)); glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix)); // 绘制多个圆柱 glBindVertexArray(cylinderVAO); for (GLuint i = 0; i < 4; i++) { glm::mat4 modelMatrix(1.0f); modelMatrix = glm::translate(modelMatrix, glm::vec3(i * 1.0f, 0.0f, 0.0f)); // 横向排列圆柱 modelMatrix = glm::scale(modelMatrix, glm::vec3(0.5f, 0.5f, 0.5f)); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(modelMatrix)); glDrawElements(GL_TRIANGLES, 60, GL_UNSIGNED_BYTE, nullptr); } // 绘制平面(调整位置到圆柱下方) glBindVertexArray(planeVAO); glm::mat4 planeModel(1.0f); planeModel = glm::translate(planeModel, glm::vec3(1.5f, -1.0f, 0.0f)); planeModel = glm::scale(planeModel, glm::vec3(2.0f, 2.0f, 1.0f)); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(planeModel)); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr); glBindVertexArray(0); glUseProgram(0);
3. 添加Shader编译/链接错误检查(可选但重要)
在CompileShader函数编译后添加:
GLint success; glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success); if (!success) { char infoLog[512]; glGetShaderInfoLog(shaderID, 512, nullptr, infoLog); cout << "Shader编译失败:\n" << infoLog << endl; }
在CreateShaderProgram函数链接后添加:
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success) { char infoLog[512]; glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog); cout << "Program链接失败:\n" << infoLog << endl; }
内容的提问来源于stack exchange,提问作者MachoMan
相关产品推荐
相关产品推荐

