最简单的曲面细分着色器(Tesselation Shader)【OpenGL】【GLSL】

发表于2018-02-07
评论0 3.3k浏览
效果如图:

按 ‘m’ 键后

代码及详细注释如下:
GLuint program;  
GLuint vao;  
void startup()  
{  
    static const char * vs_source[] =  
    {  
        "#version 410 core                                                 \n"  
        "                                                                  \n"  
        "void main(void)                                                   \n"  
        "{                                                                 \n"  
        "    const vec4 vertices[] = vec4[](vec4( 0.25, -0.25, 0.5, 1.0),  \n"  
        "                                   vec4(-0.25, -0.25, 0.5, 1.0),  \n"  
        "                                   vec4( 0.25,  0.25, 0.5, 1.0)); \n"  
        "                                                                  \n"  
        "    gl_Position = vertices[gl_VertexID];                          \n"  // 根据当前处理的顶点 ID 为顶点位置赋值  
        "}                                                                 \n"  
    };  
    // http://www.cnblogs.com/zenny-chen/p/4280100.html  
    static const char * tcs_source[] =  
    {  
        "#version 410 core                                                                 \n"  
        "                                                                                  \n"  
        "layout (vertices = 3) out;                                                        \n"  // out-patch 的顶点个数,细分控制着色器将会被执行3次  
        "                                                                                  \n"  
        "void main(void)                                                                   \n"  
        "{                                                                                 \n"  // 仅在第一次执行(第一个顶点)时赋值(控制细分程度)  
        "    if (gl_InvocationID == 0)                                                     \n"  
        "    {                                                                             \n"    
        "        gl_TessLevelInner[0] = 5.0;                                               \n"  // 内部划分5个区域(新增4排顶点,见下图)  
        "        gl_TessLevelOuter[0] = 5.0;                                               \n"  // 左边划分5段  
        "        gl_TessLevelOuter[1] = 5.0;                                               \n"  // 右边划分5段  
        "        gl_TessLevelOuter[2] = 5.0;                                               \n"  // 下边划分5段  
        "    }                                                                             \n"  
        "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;     \n"  // 通常直接将 in-patch 顶点赋给 out-patch 顶点(也可以新建或移除)  
        "}                                                                                 \n"  
    };  
    static const char * tes_source[] =  
    {  
        "#version 410 core                                                                 \n"  
        "                                                                                  \n"  
        "layout (triangles, equal_spacing, cw) in;                                         \n"   // 指定图元生成域、细分坐标空间、图元的面朝向   
        //"layout (triangles, equal_spacing, cw, point_mode) in;                             \n" // 输出点模式  
        "                                                                                  \n"  
        "void main(void)                                                                   \n"  
        "{                                                                                 \n"    
        "    gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) +                       \n"  // gl_TessCoord:细分后的新增坐标(插值比例)  
        "                  (gl_TessCoord.y * gl_in[1].gl_Position) +                       \n"  // 根据 input-patch 生成输出顶点的位置  
        "                  (gl_TessCoord.z * gl_in[2].gl_Position);                        \n"  // 每个细分坐标都会让 TES 的执行一次  
        "}                                                                                 \n"  
    };  
    static const char * fs_source[] =  
    {  
        "#version 410 core                                                 \n"  
        "                                                                  \n"  
        "out vec4 color;                                                   \n"  
        "                                                                  \n"  
        "void main(void)                                                   \n"  
        "{                                                                 \n"  
        "    color = vec4(0.0, 0.8, 1.0, 1.0);                             \n"  
        "}                                                                 \n"  
    };  
    program = glCreateProgram();  
    GLuint vs = glCreateShader(GL_VERTEX_SHADER);  
    glShaderSource(vs, 1, vs_source, NULL);  
    glCompileShader(vs);  
    // Tesselation Control Shader  
    GLuint tcs = glCreateShader(GL_TESS_CONTROL_SHADER);  
    glShaderSource(tcs, 1, tcs_source, NULL);  
    glCompileShader(tcs);  
    // Tesselation Evaluation Shader  
    GLuint tes = glCreateShader(GL_TESS_EVALUATION_SHADER);  
    glShaderSource(tes, 1, tes_source, NULL);  
    glCompileShader(tes);  
    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);  
    glShaderSource(fs, 1, fs_source, NULL);  
    glCompileShader(fs);  
    glAttachShader(program, vs);  
    glAttachShader(program, tcs);  
    glAttachShader(program, tes);  
    glAttachShader(program, fs);  
    glLinkProgram(program);  
    glGenVertexArrays(1, &vao);  
    glBindVertexArray(vao);  
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);  
}  
void render()  
{  
    static const GLfloat green[] = { 0.0f, 0.25f, 0.0f, 1.0f };  
    glClearBufferfv(GL_COLOR, 0, green);  
    glUseProgram(program);  
    glDrawArrays(GL_PATCHES, 0, 3);  
    glutSwapBuffers();  
}  
void shutdown()  
{  
    glDeleteVertexArrays(1, &vao);  
    glDeleteProgram(program);  
}  
void reshape(int width, int height)  
{  
    glViewport(0, 0, width, height);  
    GLfloat  aspect = GLfloat(width) / height;  
    //glutPostRedisplay();  
}  
void keyboard(unsigned char key, int x, int y)  
{  
    switch (key)  
    {  
        case 'q': case 'Q': case 033 /* Escape key */:  
            exit(EXIT_SUCCESS);  
            break;  
        case 'm':   // 切换填充模式或镂空模式  
        {  
            static GLenum mode = GL_FILL;  
            mode = (mode == GL_FILL ? GL_LINE : GL_FILL);  
            glPolygonMode(GL_FRONT_AND_BACK, mode);  
            break;  
        }  
    }  
    glutPostRedisplay();  
}  
int _tmain(int argc, char* argv[])  
{  
    glutInit(&argc, argv);  
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA /*| GLUT_STENCIL | GLUT_DEPTH*/);  
    glutInitWindowPosition(100, 100);  
    glutInitWindowSize(512, 512);  
    glutCreateWindow("TesselateTri"); // get an openGL context  
    GLenum err = glewInit(); // init glew  
    if (err != GLEW_OK)  
    {  
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));  
        exit(-2);  
    }  
    startup();  
    glutDisplayFunc(render);  
    glutReshapeFunc(reshape);  
    glutKeyboardFunc(keyboard);  
    glutMainLoop();  
    return 0;  
}  

内部新增的4排顶点示意图

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引