You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 04:05:14