OpenGL曲面细分绘制六边形仅显示三角形问题求助
问题:OpenGL曲面细分绘制六边形却显示三角形
尝试使用OpenGL曲面细分技术绘制六边形,但运行代码后仅显示三角形。硬件为Nvidia 4080显卡,驱动已更新至最新版本,依赖库检查无异常。
代码如下:
#include <glad/glad.h> #include <GLFW/glfw3.h> #include <glm/glm.hpp> #include <glm/gtc/type_ptr.hpp> #include <glm/gtc/matrix_transform.hpp> #include <iostream> glm::vec3 hexagonPoints[] = { {0.0f, 0.5f, 0.0f}, {0.433f, 0.25f, 0.0f}, {0.433f, -0.25f, 0.0f}, {0.0f, -0.5f, 0.0f}, {-0.433f, -0.25f, 0.0f}, {-0.433f, 0.25f, 0.0f}, }; GLuint hexagonVBO, hexagonVAO; const char* vertexShaderSource = R"( #version 400 core layout (location = 0) in vec3 aPos; void main() { gl_Position = vec4(aPos, 1.0); } )"; const char* tessControlShaderSource = R"( #version 400 core layout(vertices = 6) out; void main() { if (gl_InvocationID == 0) { gl_TessLevelInner[0] = 1.0; gl_TessLevelInner[1] = 1.0; gl_TessLevelOuter[0] = 1.0; gl_TessLevelOuter[1] = 1.0; gl_TessLevelOuter[2] = 1.0; gl_TessLevelOuter[3] = 1.0; } gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; } )"; const char* tessEvalShaderSource = R"( #version 400 core layout(triangles) in; void main() { gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) + (gl_TessCoord.y * gl_in[1].gl_Position) + (gl_TessCoord.z * gl_in[2].gl_Position); } )"; const char* fragmentShaderSource = R"( #version 400 core out vec4 FragColor; void main() { FragColor = vec4(1.0, 0.0, 0.0, 1.0); } )"; void setupHexagonVAO() { glGenVertexArrays(1, &hexagonVAO); glBindVertexArray(hexagonVAO); glGenBuffers(1, &hexagonVBO); glBindBuffer(GL_ARRAY_BUFFER, hexagonVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(hexagonPoints), hexagonPoints, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); } GLuint compileShader(GLenum type, const char* source) { GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &source, nullptr); glCompileShader(shader); int success; char infoLog[512]; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(shader, 512, nullptr, infoLog); std::cerr << "Error compiling shader: " << infoLog << std::endl; } return shader; } GLuint createTessellationProgram() { GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource); GLuint tessControlShader = compileShader(GL_TESS_CONTROL_SHADER, tessControlShaderSource); GLuint tessEvalShader = compileShader(GL_TESS_EVALUATION_SHADER, tessEvalShaderSource); GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource); GLuint shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, tessControlShader); glAttachShader(shaderProgram, tessEvalShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); int success; char infoLog[512]; glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog); std::cerr << "Error linking shader program: " << infoLog << std::endl; } glDeleteShader(vertexShader); glDeleteShader(tessControlShader); glDeleteShader(tessEvalShader); glDeleteShader(fragmentShader); return shaderProgram; } int main() { if (!glfwInit()) { std::cerr << "Failed to initialize GLFW" << std::endl; return -1; } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); GLFWwindow* window = glfwCreateWindow(800, 600, "Tessellation Hexagon", nullptr, nullptr); if (!window) { std::cerr << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cerr << "Failed to initialize GLAD" << std::endl; return -1; } glViewport(0, 0, 800, 600); glEnable(GL_DEPTH_TEST); setupHexagonVAO(); GLuint tessShaderProgram = createTessellationProgram(); while (!glfwWindowShouldClose(window)) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(tessShaderProgram); glPatchParameteri(GL_PATCH_VERTICES, 6); glBindVertexArray(hexagonVAO); glDrawArrays(GL_PATCHES, 0, 6); glfwSwapBuffers(window); glfwPollEvents(); } glDeleteVertexArrays(1, &hexagonVAO); glDeleteBuffers(1, &hexagonVBO); glDeleteProgram(tessShaderProgram); glfwTerminate(); return 0; }
运行后仅显示红色三角形。
问题分析与解决
代码存在两个关键错误,导致无法正确渲染六边形:
曲面细分评估着色器拓扑不匹配
当前评估着色器使用layout(triangles) in;,但传入的是6顶点的面片(patch),OpenGL会自动将6顶点拆分为两个三角形,且仅渲染其中一个。需要将评估着色器的输入拓扑改为layout(polygon, equal_spacing, ccw) in;,以支持多边形面片的细分计算。细分等级设置错误
- 六边形属于多边形,
gl_TessLevelInner仅需设置1个值(控制内部细分密度),原代码错误设置了2个值。 - 六边形有6条边,
gl_TessLevelOuter需要设置6个值(对应每条边的细分密度),原代码仅设置了4个,且所有等级为1.0意味着无细分效果。
- 六边形属于多边形,
修改后的关键代码
曲面细分控制着色器
#version 400 core layout(vertices = 6) out; void main() { if (gl_InvocationID == 0) { gl_TessLevelInner[0] = 4.0; // 内部细分等级,值越高越平滑 // 为六边形6条边设置外部细分等级 gl_TessLevelOuter[0] = 4.0; gl_TessLevelOuter[1] = 4.0; gl_TessLevelOuter[2] = 4.0; gl_TessLevelOuter[3] = 4.0; gl_TessLevelOuter[4] = 4.0; gl_TessLevelOuter[5] = 4.0; } gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; }
曲面细分评估着色器
#version 400 core layout(polygon, equal_spacing, ccw) in; void main() { vec4 pos = vec4(0.0); // 遍历所有输入顶点,用细分坐标插值计算最终位置 for (int i = 0; i < gl_in.length(); i++) { pos += gl_TessCoord[i] * gl_in[i].gl_Position; } gl_Position = pos; }
修改后效果
调整后,OpenGL会将6顶点面片作为多边形进行曲面细分,渲染出平滑的六边形,细分等级可根据需求调整数值(值越高,多边形边缘和内部越平滑)。
内容的提问来源于stack exchange,提问作者Airgetlams
相关产品推荐
相关产品推荐

