笔记:OpenGL SuperBible - Tessellation

Tessellation: a process of breaking a high-order primitive/surface (AKA patches) into many smaller, simpler primitives such as points, lines and triangles for rendering.

Tessellation phase sits directly after vertex shading stage and is made up of 3 parts: 

1) tessellation control shader, 

2) fixed-function tessellation engine, 

3) tessellation evaluation shader.


Tessellation control shader ( AKA control shader / TCS )

This shader takes its input from the vertex shader and is primarily responsible for: 

1) the determination of the level of tessellation that will be sent to the tessellation engine, 

2) the generation of data that will be sent to the tessellation evaluation shader that is run after tessellation has occurred. 

Tessellation breaks down high-order surfaces ( patches ) into points, lines, or triangles. Each patch is formed from a number of control points. The number of control points per patch is configurable and set by callingglPatchParameteri()with pnameset to GL_PATCH_VERTICESand valueset to the number of control points thatwill be used to construct each patch. The prototype:

void glPatchParameteri(GLenum pname, GLint value);

By default, # of control points per patch is 3. (So, we don't need to call it in the examples.)

When tessellation is active, thevertex shader runs once per control point whilst thetessellation control shader runs in batches on groups of control points (CPs)where the size of each batch is the same as the number of vertices per patch.That is, vertices are used as control points, and the result of the vertex shader is passed in batches to the tessellation control shader as its input. # of control points per patch can be changed such that # of control points that is output by the tessellation control shader can be different from # of control points that itconsumes. # of control points produced by the control shader is set using an output layout qualifier in the control shader’s source code. Such a layout qualifier looks like:

layout (vertices = N) out; 

N is the number of control points per patch. 

The output tessellation factors are written to thegl_TessLevelInnerand gl_TessLevelOuterbuilt-in output variables, whereas any other data that is passed down the pipeline is written touser-defined output variables (those declared using the out keyword,or the special built-in gl_outarray) as normal. 

#version 410 core

// sets # of output control points to three
layout (vertices = 3) out;

void main(void)
{
    // sets the inner and outer tessellation level to 5
    if (gl_InvocationID == 0) {
        gl_TessLevelInner[0] = 5.0;
        gl_TessLevelOuter[0] = 5.0;
        gl_TessLevelOuter[1] = 5.0;
        gl_TessLevelOuter[2] = 5.0;
    }
    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}

The built-ininput variable gl_InvocationIDis used to index into the gl_inand gl_outarrays. This variable contains the zero-based index of the control point within the patch being processed by the current invocation of thetessellation control shader. 


The Tessellation Engine 

Fixed function part.

The tessellation engine produces the parameters that are fed to the invocations of tessellation evaluation shader, which it then uses to transform the resulting primitives and get them ready for rasterization. 


Tessellation Evaluation Shaders (TES)

The tessellation control shader processes the incoming control points and sets tessellation factors that are used to break down the patch.

Then tessellation engine receives a patch, breaks it into primitives and and passes the vertices (representing the primitives) to tessellation evaluation shader.

TES runs an invocation for each vertex. 
When tessellation level is high, it means TES could run an extremely large number of times, and so you should be careful with (慎用) complex evaluation shaders and high tessellation levels.

#version 410 core

// a layout qualifier that sets the tessellation mode: triangles.
// equal_spacing: new vertices should be generated equally spaced along the tessellated polygon edges
// cw: a clockwise vertex winding order should be used for the generated triangles.
layout (triangles, equal_spacing, cw) in;
void main(void)
{
    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);
}

gl _ TessCoord : the barycentric coordinate of the vertex generated by the tessellator.

gl_in[0].gl_Position: gl_Positionmember of the gl_in[]array of structures. 

This matches the gl_outstructure written to in the tessellation control shader.

the tessellated output patch is the exact same shape asthe original, incoming triangular patch. 



In order to see the results of the tessellator, we need to tell OpenGL todraw only the outlines of the resulting triangles. To do this, we callglPolygonMode(), whose prototype is 

void glPolygonMode(GLenum face, GLenum mode);

face parameter specifies what type of polygons we want to affect.

As we want to affect everything, we set it toGL_FRONT_AND_BACK

mode says how we want our polygons to be rendered. 

As we want to render in wireframe mode (i.e., lines), we set this to GL_LINE


附完整代码:

// Include the "sb6.h" header file
#include "sb6.h"
#include <cmath>

GLuint compile_shaders(void)
{
    GLuint vertex_shader;
    GLuint fragment_shader;
    GLuint tessellation_control_shader;
    GLuint tessellation_evaluation_shader;
    GLuint program;
    // Source code for vertex shader
    static const GLchar * vertex_shader_source[] = {
        "#version 410 core \n"
        "void main(void) \n"
        "{ \n"
        "   const vec4 vertices[3] = vec4[3](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"
        "   gl_Position = vertices[gl_VertexID];  \n"
        "} \n"
    };
    // Source code for fragment shader
    static const GLchar * fragment_shader_source[] = {
        "#version 410 core \n"
        "out vec4 color; \n"
        " \n"
        "void main(void) \n"
        "{ \n"
        "    color = vec4(0.0, 0.8, 1.0, 1.0);              \n"
        "} \n"
    };
    
    static const GLchar * control_shader_source[] = {
        "#version 410 core \n"
        "layout (vertices = 3) out; \n"
        "void main(void) \n"
        "{ \n"
        "   if (gl_InvocationID == 0) { \n"
        "       gl_TessLevelInner[0] = 5.0; \n"
        "       gl_TessLevelOuter[0] = 5.0; \n"
        "       gl_TessLevelOuter[1] = 5.0; \n"
        "       gl_TessLevelOuter[2] = 5.0; \n"
        "   } \n"
        "   gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; \n"
        "} \n"

    };
    
    static const GLchar * eval_shader_source[] = {
        "#version 410 core \n"
        "layout (triangles, equal_spacing, cw) in; \n"
        "void main(void) \n"
        "{ \n"
        "   gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position + \n"
        "                  gl_TessCoord.y * gl_in[1].gl_Position + \n"
        "                  gl_TessCoord.z * gl_in[2].gl_Position); \n"
        "} \n"
    };
    
    // Create and compile vertex shader
    vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
    glCompileShader(vertex_shader);
    
    tessellation_control_shader = glCreateShader(GL_TESS_CONTROL_SHADER);
    glShaderSource(tessellation_control_shader, 1, control_shader_source, NULL);
    glCompileShader(tessellation_control_shader);
    
    tessellation_evaluation_shader = glCreateShader(GL_TESS_EVALUATION_SHADER);
    glShaderSource(tessellation_evaluation_shader, 1, eval_shader_source, NULL);
    glCompileShader(tessellation_evaluation_shader);
    
    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
    glCompileShader(fragment_shader);
    
    // Create program, attach shaders to it, and link it
    program = glCreateProgram();
    glAttachShader(program, vertex_shader);
    glAttachShader(program, tessellation_control_shader);
    glAttachShader(program, tessellation_evaluation_shader);
    glAttachShader(program, fragment_shader);
    
    glLinkProgram(program);
    
    // Delete the shaders as the program has them now
    glDeleteShader(vertex_shader);
    glDeleteShader(tessellation_control_shader);
    glDeleteShader(tessellation_evaluation_shader);
    glDeleteShader(fragment_shader);
    
    return program;
}

class my_application : public sb6::application {
public:
    // Our rendering function
    void render(double currentTime) {
        const GLfloat bgcolor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
        glClearBufferfv(GL_COLOR, 0, bgcolor);
        
        // Use the program object we created earlier for rendering
        glUseProgram(rendering_program);
        
        GLfloat attrib[] = { (float)sin(currentTime) * 0.5f,
            (float)cos(currentTime) * 0.6f,
            0.0f, 0.0f };
        const GLfloat color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
        
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        
        // Update the value of input attribute 0
        glVertexAttrib4fv(0, attrib);
        
        // Update the value of input attribute 1
        // It is the variable declared in vertex shader:
        // "layout (location = 1) in vec4 color; \n"
        glVertexAttrib4fv(1, color);
        
        glPointSize(5.0f);
        
        // Draw one triangle
        glDrawArrays(GL_PATCHES, 0, 3);
    }
    // <snip>
    void startup()
    {
        rendering_program = compile_shaders();
        glGenVertexArrays(1, &vertex_array_object);
        glBindVertexArray(vertex_array_object);
    }
    void shutdown()
    {
        glDeleteVertexArrays(1, &vertex_array_object);
        glDeleteProgram(rendering_program);
        glDeleteVertexArrays(1, &vertex_array_object);
    }
private:
    GLuint rendering_program;
    GLuint vertex_array_object;
};

// Our one and only instance of DECLARE_MAIN
DECLARE_MAIN(my_application);


Reference: SuperBible 6th, Chapter 3.






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值