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

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;
}

运行后仅显示红色三角形。


问题分析与解决

代码存在两个关键错误,导致无法正确渲染六边形:

  1. 曲面细分评估着色器拓扑不匹配
    当前评估着色器使用layout(triangles) in;,但传入的是6顶点的面片(patch),OpenGL会自动将6顶点拆分为两个三角形,且仅渲染其中一个。需要将评估着色器的输入拓扑改为layout(polygon, equal_spacing, ccw) in;,以支持多边形面片的细分计算。

  2. 细分等级设置错误

    • 六边形属于多边形,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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 02:17:03