OpenGL中C++实现的圆柱如何添加上下底面?
给圆柱添加上下底面的解决方案
你的现有代码已经实现了圆柱的侧面,但上下底面是独立的圆形平面,需要单独构造顶点并绘制。下面一步步帮你完善:
1. 先优化现有侧面生成代码
你原来的GetUV函数里有多余的cv和sv变量(v是高度方向,不需要三角函数),可以先简化:
glm::vec3 CMyApp::GetUV(float u, float v) { float r = 0.5; // 半径 float h = 2; // 高度 u *= 2 * 3.1415f; // 把[0,1]的u映射到0~2π v *= h; // 把[0,1]的v映射到0~h float cu = cosf(u), su = sinf(u); return glm::vec3(r * cu, v, -r * su); }
同时补全Init函数里的u和v赋值,改用动态数组避免栈溢出:
// 侧面顶点数:(圆周分段数N+1) × (高度分段数M+1) int sideVertCount = (N + 1) * (M + 1); // 总顶点数:侧面 + 两个底面(每个底面N+1个顶点:圆心+N个圆周点) std::vector<Vertex> verts(sideVertCount + 2 * (N + 1)); int idx = 0; // 生成侧面顶点 for (int i = 0; i <= N; ++i) { float u = static_cast<float>(i) / N; // 圆周方向参数,范围[0,1] for (int j = 0; j <= M; ++j) { float v = static_cast<float>(j) / M; // 高度方向参数,范围[0,1] glm::vec3 pos = GetUV(u, v); verts[idx].position = pos; // 侧面UV直接用u和v,方便贴图 verts[idx].uv = glm::vec2(u, v); // 侧面法线:径向向外(忽略y分量,归一化) verts[idx].normal = glm::normalize(glm::vec3(pos.x, 0.0f, pos.z)); idx++; } }
2. 添加上下底面的顶点生成
上下底面是圆心在(0, 0, 0)和(0, h, 0)的圆形,用**三角扇(GL_TRIANGLE_FAN)**绘制最高效(圆心+一圈点就能生成整个圆面):
float r = 0.5f; float h = 2.0f; // 生成下底面(y=0,法线向下) // 先添加圆心 verts[idx].position = glm::vec3(0.0f, 0.0f, 0.0f); verts[idx].uv = glm::vec2(0.5f, 0.5f); // 圆心对应UV纹理中心 verts[idx].normal = glm::vec3(0.0f, -1.0f, 0.0f); idx++; // 添加圆周上的点 for (int i = 0; i <= N; ++i) { float u = static_cast<float>(i) / N * 2 * 3.1415f; float cu = cosf(u), su = sinf(u); verts[idx].position = glm::vec3(r * cu, 0.0f, -r * su); // 把圆周点映射到UV纹理的[0,1]范围(圆心在0.5,0.5) verts[idx].uv = glm::vec2(0.5f + 0.5f * cu, 0.5f + 0.5f * su); verts[idx].normal = glm::vec3(0.0f, -1.0f, 0.0f); idx++; } // 生成上底面(y=h,法线向上) verts[idx].position = glm::vec3(0.0f, h, 0.0f); verts[idx].uv = glm::vec2(0.5f, 0.5f); verts[idx].normal = glm::vec3(0.0f, 1.0f, 0.0f); idx++; for (int i = 0; i <= N; ++i) { float u = static_cast<float>(i) / N * 2 * 3.1415f; float cu = cosf(u), su = sinf(u); verts[idx].position = glm::vec3(r * cu, h, -r * su); verts[idx].uv = glm::vec2(0.5f + 0.5f * cu, 0.5f + 0.5f * su); verts[idx].normal = glm::vec3(0.0f, 1.0f, 0.0f); idx++; }
3. 分别绘制侧面和底面
在渲染函数中,需要用不同的图元类型绘制不同部分:
// 绘制侧面(用三角带或三角形,根据你的原始逻辑选择) glDrawArrays(GL_TRIANGLE_STRIP, 0, sideVertCount); // 绘制下底面(三角扇:从第sideVertCount个顶点开始,共N+1个顶点) glDrawArrays(GL_TRIANGLE_FAN, sideVertCount, N + 1); // 绘制上底面(从sideVertCount + N+1个顶点开始,共N+1个顶点) glDrawArrays(GL_TRIANGLE_FAN, sideVertCount + N + 1, N + 1);
关键细节说明
- 法线设置:侧面法线径向向外,上下底面法线分别指向y轴负方向和正方向,这样光照计算才会正确显示面的朝向。
- UV映射:底面的UV把圆形映射到正方形纹理的中心区域,避免贴图拉伸变形。
- 动态数组:用
std::vector<Vertex>替代固定大小的数组,避免栈溢出,也更灵活。
内容的提问来源于stack exchange,提问作者chuck
相关产品推荐
相关产品推荐

