zoukankan      html  css  js  c++  java
  • OpenGL

    http://blog.sina.com.cn/s/blog_8c7d49f20102v4qm.html

    Patch is just an ordered list of vertices (在tessellation shader里面比较重要的概念就是这个patch,patch是一系列的顶点,OpenGL规定patch的vertex数量必须至少大于等于3)

    The tessellation process doesn’t operate on OpenGL’s classic geometric primitives: points, lines, and triangles, but uses a new primitive called a patch (Tessellation shader就是针对patch来进行处理的而并非点,县,三角形)

     

    Patch – are processed by all of active shading stage in the pipeline (patch可被所有的shader处理)

    Two shading stages of Tessellation shading:

    1.      Tessellation Control Shader (optional)

    In tessellation control shader, gl_PatchVerticesIn provides the number of elements in gl_in (gl_in 用于在tessellation control shader里面访问传进的来patch里面的顶点)

    gl_out 用于控制patch里面的vertex从tessellation control shader输出后的属性

    gl_InvocationID is used to access the specific vertex of a patch (gl_InvocationID 用于访问传入patch里的特定顶点)

    Layout (vertices = *) out; (用于指定输出的patch里面有多少个顶点)

               gl_TessLevelInner
                   Specify how the interior of the domain is subdivided and stored in a two element array named gl_TessLevelInner(指定多边形内部如何细分)
             gl_TessLevelOuter
                    Control how the perimeter of the domain is subdivided, and is stored in an implicitly declared four-element array named gl_TessLevelOuter(指定多边形边界上的边被如何细分)
              gl_TessLevelInner & gl_TessLevelOuter 根据多边形内部区域的类型会有不同的分割法
     
    Tessellation Evaluation Shader (optional)

    The TES is executed on all generated domain locations.Positions each of the vertices in the final mesh (TES是针对从tessellation control shader 里面通过细分生成的顶点来进行运算,通过gl_in和gl_VocationID来访问我们传入的patch的一系列顶点信息,结合gl_TessCoord访问我们生成的新顶点的纹理信息来计算新的坐标位置,从而实现细分多边形的效果)

    layout (quads, equal_spacing, ccw) in; (指定新生成的多边形类型等信息)

    glPatchParameteri() -- 告诉程序我们定义多少个顶点为一个patch


    barrier() – .....

    If you have additional per-vertex attribute values, either for input or output, these need to be declared as either in or out arrays in your tessellation control shader (需要传入TCS额外的顶点信息,需要定义额外in & out array)


    glPatchParameterfv() -- can be used to set the inner and outer-tessellation levels(可以用于指定inner和outer的数值,当然我们也可以在tessellation control shader里面通过gl_TessLevelInner & gl_TessLevelOuter直接指定)

    三中不同类型的domain -- 会决定我们inner和outer的具体含义:

    Quad Tessellation:

    …..

    Isoline  Tessellation:

    Use only two of the outer-tessellation levels to determine the amount of subdivision

    …..

    Triangle Tessellation:

    Triangular domains use barycentric coordinates to specify their Tessellation coordinates

    …..

    最终渲染效果:

    - Tessellation Shader" title="OpenGL - Tessellation Shader" height="291" width="452">

    - Tessellation Shader" title="OpenGL - Tessellation Shader" height="318" width="448">

    - Tessellation Shader" title="OpenGL - Tessellation Shader" height="291" width="455">

    - Tessellation Shader" title="OpenGL - Tessellation Shader" height="298" width="444">

    Main.cpp Source Code below:
    #include

    #include

    #include

    // TODO: 在此处引用程序需要的其他头文件
    #include
    #include "vgl.h"
    #include "mat.h"
    #include "LoadShaders.h"
    #include "Shapes/Teapot.h"

    using namespace std;

    GLuint  PM;  // Projection matrix
    GLuint  MVM;     // Model view matrix

    GLuint  InnerL;  // Inner tessellation paramter
    GLuint  OuterL;  // Outer tessellation paramter

    GLfloat  Inner = 1.0;
    GLfloat  Outer = 1.0;

    #define SQUARE_VERTEX_NUMBER 4

    //----------------------------------------------------------------------------

    void init( void )
    {
        //create shader and link program first
        ShaderInfo shaders[] = {
            { GL_VERTEX_SHADER,          "square.vert" },
            { GL_TESS_CONTROL_SHADER,    "square.cont" },
            { GL_TESS_EVALUATION_SHADER, "square.eval" },
            { GL_FRAGMENT_SHADER,        "square.frag" },
            { GL_NONE, NULL }
        };

        //Shader program
        GLuint program;

        //load shaders
        program = LoadShaders(shaders);

        //link shader program and use it
        glUseProgram(program);

        //vertex array
        GLuint VA;
        glGenVertexArrays(1, &VA);
        glBindVertexArray(VA);

        //Vertex buffer
        GLuint VB;
        glGenBuffers(1, &VB);
        glBindBuffer(GL_ARRAY_BUFFER, VB);

        //define square vertex data
        const GLfloat square_vertex_data[SQUARE_VERTEX_NUMBER][2] = {
            { 1.0, 1.0 },
            { -1.0, 1.0},
            { -1.0, -1.0},
            { 1.0, -1.0}
        };

        //vertex buffer data
        glBufferData(GL_ARRAY_BUFFER, sizeof(square_vertex_data), square_vertex_data, GL_STATIC_DRAW);

        //Obtain vertex position in program
        GLint vPostionIndex = glGetAttribLocation(program, "vPosition");

        //Enable vertex attribute
        glEnableVertexAttribArray( vPostionIndex );

        //define an array of generic vertex attribute data for shader (让shader知道怎么去读取我们传入的vertex 信息)
        glVertexAttribPointer(vPostionIndex, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));

        //Obtain uniform variable of program
        PM = glGetUniformLocation(program, "PJ");
        MVM = glGetUniformLocation(program, "MV");

        InnerL = glGetUniformLocation(program, "inner");
        OuterL = glGetUniformLocation(program, "outer");

        //Set some default value for uniform variable
        glUniform1f(InnerL, Inner);
        glUniform1f(OuterL, Outer);

        mat4  modelview = Translate( 0.0, 0.0, -2.0 ) *    RotateX( -50.0 );
       
        glUniformMatrix4fv( MVM, 1, GL_TRUE, modelview );

        //Define how many vertices composed one patch (定义多少个vertices定义一个patch)
        glPatchParameteri(GL_PATCH_VERTICES, 4);

        //Enable some relative setting
        glEnable(GL_DEPTH_TEST);

        glClearColor( 0.0, 0.0, 0.0, 1.0 );
    }

    //----------------------------------------------------------------------------

    void display( void )
    {
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
       
        glUniform1f(InnerL, Inner);

        glUniform1f(OuterL, Outer);

        glDrawArrays(GL_PATCHES, 0, SQUARE_VERTEX_NUMBER);

        glutSwapBuffers();
    }

    //----------------------------------------------------------------------------

    void reshape( int width, int height )
    {
        glViewport( 0, 0, width, height );

        GLfloat  aspect = GLfloat(width)/height;

        mat4  projection = Perspective( 60.0, aspect, 1, 3 );
       
        glUniformMatrix4fv( PM, 1, GL_TRUE, projection );

        glutPostRedisplay();
    }

    //----------------------------------------------------------------------------

    void keyboard( unsigned char key, int x, int y )
    {
        switch ( key ) {
        case 'q': case 'Q': case 033 :
            exit( EXIT_SUCCESS );
            break;

        case 'i':
            Inner--;
            if ( Inner < 1.0 )  Inner = 1.0;
            glUniform1f( InnerL, Inner );
            break;

        case 'I':
            Inner++;
            if ( Inner > 64 )  Inner = 64.0;
            glUniform1f( InnerL, Inner );
            break;

        case 'o':
            Outer--;
            if ( Outer < 1.0 )  Outer = 1.0;
            glUniform1f( OuterL, Outer );
            break;

        case 'O':
            Outer++;
            if ( Outer > 64 )  Outer = 64.0;
            glUniform1f( OuterL, Outer );
            break;

        case 'r':
            Inner = 1.0;
            Outer = 1.0;
            glUniform1f( InnerL, Inner );
            glUniform1f( OuterL, Outer );
            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 main( int argc, char *argv[] )
    {
        glutInit( &argc, argv );
        glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
        glutInitWindowSize( 512, 512 );
        glutInitContextVersion( 3, 2 );
        glutInitContextProfile( GLUT_CORE_PROFILE );
        glutCreateWindow( "teapot" );

         glewExperimental = GL_TRUE;    //注意这里有个坑 -- 这一句很关键,不加这一句gl_GenVertexArray()会报错,好像说是GLEW对openGL的core context有一些问题

          //   http://stackoverflow.com/questions/22813625/0xc0000005-access-violation-executing-location-0x00000000-opengl


        GLenum error = glewInit();

        if( error != GLEW_OK )
        {
            cout<<"glewInit failed, aborting"<<endl;
        }

        if ( GLEW_ARB_vertex_array_object == NULL )
        {
            cout<<"GLEW_ARB_vertex_array_object = NULL"<<endl;
        }

        cout<<"Error info:"<<glGetError()<<endl;

        init();

        glutDisplayFunc( display );
        glutReshapeFunc( reshape );
        glutKeyboardFunc( keyboard );

        glutMainLoop();
        return 0;
    }

    square.vert source code below:

    #version 400 core

    in  vec4  vPosition;

    void main()
    {
        //gl_Position is used to access the vertex position that is input from application
        gl_Position = vPosition;
    }

    square.cont source code below:

    #version 400 core

    //The main purpose of tessellation control shader is:
    //Generate the tessellation output patch vertices that are passed to the tessellation
    //evaluation shader, as well as update any per-vertex

    //Define how many vertices will be used as one patch
    layout (vertices = 4) out;

    //uniform type is used to define the variable that can be used to communicate between shader and application
    uniform float inner;

    uniform float outer;

    void main()
    {
        //gl_TessLevelInner is used to define:
        //how the interior of the domain is subdivided and stored in a two element array named    
        gl_TessLevelInner[0] = inner;
        gl_TessLevelInner[1] = inner;
       
        //gl_TessLevelOuter is used to define:
        //how the perimeter of the domain is subdivided, and is stored in an
        //implicitly declared four-element array
        gl_TessLevelOuter[0] = outer;
        gl_TessLevelOuter[1] = outer;
        gl_TessLevelOuter[2] = outer;
        gl_TessLevelOuter[3] = outer;
       
        //gl_in is used to access the number of elements that are define by glPatchParameteri()
        //glPatchParameteri() define how many vertices as a patch
        //gl_out is used to access the output vertex position of tessellation control shader
        //gl_in vertex shader structure below:
        //in gl_PerVertex {
        //        vec4 gl_Position;
        //        float gl_PointSize;
        //        float gl_ClipDistance[]
        //} gl_in[gl_PatchVerticesIn];   
        //gl_out vertex shader structure is similar to gl_in structure
        //gl_InvocationID is used to access the specific vertex of a patch
        gl_out[gl_InvocationID].gl_Position =  gl_in[gl_InvocationID].gl_Position;
    }

    square.eval source code below:

    #version 400 core

    //The main purpose of tessellation evaluation shader is:
    //configure the primitive generator, which is done using a layout directive
    //Specifying the face winding for generated primitives
    //(the order the vertices are issued determines the facedness of the primitive)
    layout (quads, equal_spacing, ccw) in;

    //The TES is executed on all generated domain locations.
    //The bound tessellation evaluation shader is
    //executed one for each tessellation coordinate that the primitive generator
    //Tessellation Shaders emits, and is responsible for determining the position
    //of the vertex derived from the tessellation coordinate.

    uniform mat4 PJ;

    uniform mat4 MV;

    #define M_PI        3.14159265358979323846

    //----------------------------------------------------------------------------

    float Hanning( vec2 p )
    {
        p -= 0.5; // map unit square to [-.5, .5]

        float r = length( p );

        r = cos( M_PI * r / 2.0 );
        r *= r;

        return r;
    }

    void main()
    {
        //gl_TessCoord is used to access the Tessellation coordinates that are
        //generated by tessellation control shader
        float u = gl_TessCoord.x;
        float v = gl_TessCoord.y;
       
        //use Tessellation coordinates to calculate position for new vertex that
        //is generated by tessellation control shader
        #define p(i)  gl_in[i].gl_Position

        vec4 pos = v*(u*p(0) + (1-u)*p(1)) + (1-v)*(u*p(3) + (1-u)*p(2));
        pos.z = Hanning( gl_TessCoord.xy );
       
        gl_Position = PJ * MV * pos;
    }

    square.frag source code below:

    #version 400 core

    out  vec4 fColor;

    void main()
    {
        fColor = (1 - gl_FragCoord.z) * vec4( 1.0, 0.0, 0.0, 1.0 );
    }

    总结:

    tessellation shader是可选的shader,不是必须的

    tessellation shader与vertex shader不一样,tessellation shader是针对patch(一系列顶点)来处理而不是一个顶点 (因为tessellation shader需要通过传入的patch(一系列顶点)来计算新顶点的位置信息)

    tessellation control shader负责对patch的细分设定

    tessellation evaluation shader负责对TCS细分出来的顶点进行位置等信息运算从而实现LOD(level of detail -- 根据与camera的距离不同而细分程度不同)等效果

    Bezier曲线在这里是一种细分后位置的计算方法来实现曲面的平滑效果

    tessellation shader有个重要的应用就是LOD(Level of Detail),通过在判断物体与视线的距离来设定tessellation control里面的factor level从而实现近细分多,远细分少的效果

    还有一个应用叫displacement mapping,在tessellation evaluation shader里面通过tessellation coordinate的值来映射纹理(sample a texture)

  • 相关阅读:
    (三)3-5 Python生成式和生成器
    (三)3-4 Python的高阶函数和匿名函数
    Linux下安装Python3
    Python math函数库
    今日头条as,cp,_signature参数破解
    使用scrapy实现分布式爬虫
    scrapy框架持久化存储
    Python中使用rsa加密
    使用Python进行微博登录
    WebDriverWait 显示等待
  • 原文地址:https://www.cnblogs.com/mazhenyu/p/5010296.html
Copyright © 2011-2022 走看看