본문 바로가기
3D웹 프로그래밍/opengl

Opengl 테셀레이션

by 디찌s 2020. 11. 19.
728x90
반응형

테셀레이션

테셀레이션은 고차 프리미티브(Opengl에서는 패치로 알려져 있다.)를 더 작고, 단순한 여러 개의 렌더링 가능한 프리미티브로 분할하는 작업이다.

 

OpenGL은 고정 함수며 설정 가능한 테셀레이션 엔진을 포함하는데,이 테셀레이션 엔진은 사각형,삼각형,선들을 더 많고 더우우우욱 작은 점,선 삼각형등으로 분할한다!.

 

테셀레이션 컨트롤 쉐이더

세가지 테셀레이션 단계중 첫번째는 테셀레이션 컨트롤 쉐이더이다.

이 쉐이더는 버텍스 쉐이더로부터 입력을 받아 주로 두 가지 일을 수행한다. 하나는 테셀레이션 엔진에 보낼 테셀레이션의 레벨을 결정하는것이고, 두번째는 테셀레이션이 수행된 다음에 실행되는 테셀레이션 이벨류에이션 쉐이더에 보낼 데이터를 생성하는일이다.

 

Opengl에서 테셀레이션은 패치라고 부르는 고차 서피스를 점,선,삼각형 등으로 분할하는일을 수행한다.

각 패치는 여러 제어점으로 만들고 패치당 제어점 개수는 변경이 가능한데 glPatchParameteri()함수를 이용한다. 기본 패치는 제어점 3개이다.

테셀레이션이 활성활 될때 버텍스 쉐이더는 제어점당 한번씩 수행되며, 테셀레이션 컨트롤 쉐이더는 제어점들의 구룹에 대해 배치로 수행된다.

 

    static const char* tcs_source[] =
        {
            "#version 410 core                                                                 \n"
            "                                                                                  \n"
            "layout (vertices = 3) out;                                                        \n"
            "                                                                                  \n"
            "void main(void)                                                                   \n"
            "{                                                                                 \n"
            "    if (gl_InvocationID == 0)                                                     \n"
            "    {                                                                             \n"
            "        gl_TessLevelInner[0] = 7.0;                                               \n"
            "        gl_TessLevelOuter[0] = 2.0;                                               \n"
            "        gl_TessLevelOuter[1] = 7.0;                                               \n"
            "        gl_TessLevelOuter[2] = 3.0;                                               \n"
            "    }                                                                             \n"
            "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;     \n"
            "}                                                                                 \n"
        };

 

 

위 코드에 gl_Tesslevelinner,gl_TesslevelOuter는 레벨을 담당하며 inner는 내부, outer는 외부를 담당한다

 

  static const char* tes_source[] =
        {
            "#version 410 core                                                                 \n"
            "                                                                                  \n"
            "layout (triangles, equal_spacing, cw) in;                                         \n"
            "                                                                                  \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"
        };

 

위에 코드는  equal_spacing과 cw는 테셀레이트된 폴리곤 가장자리를 따라 동일한 간격으로 버텍스들이 생성되도록 하는 옵션과 시계 방향 버텍스 감기 순서를 사용하여 삼각형을 생성하도록 하는 옵션이다.

 

 

 

 

아래는 풀코드이다

 

 

/*
 * Copyright ?2012-2013 Graham Sellers
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include <sb6.h>
#include <vmath.h>
class simpleclear_app : public sb6::application
{
public:
    virtual 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;


    void init()
    {
        static const char title[] = "Simple Clear";

        sb6::application::init();

        memcpy(info.title, title, sizeof(title));
    }

    virtual void render(double currentTime)
    {
        static const GLfloat green[] = { 0.0f, 0.0f, 0.0f, 1.0f };
      
        glClearBufferfv(GL_COLOR, 0, green);

        //렌더링을 위해 생성했던 프로그램 객체를 사용한다.
        glUseProgram(rendering_program);

      

        //삼각형을 하나 그린다.
        glDrawArrays(GL_PATCHES, 0, 3);
     
    }



    GLuint compile_shaders(void) {
        GLuint vertex_shader;
        GLuint fragment_shader;
        GLuint program;
        
        //vertex shader 소스
        static const char * vertex_shader_source[] = {
            "#version 420 core                                                 \n"
            "layout (location =0)in vec4 offset;                               \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] + offset;                          \n"
            "}  \n"      
        };

        static const char* tcs_source[] =
        {
            "#version 410 core                                                                 \n"
            "                                                                                  \n"
            "layout (vertices = 3) out;                                                        \n"
            "                                                                                  \n"
            "void main(void)                                                                   \n"
            "{                                                                                 \n"
            "    if (gl_InvocationID == 0)                                                     \n"
            "    {                                                                             \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 char* tes_source[] =
        {
            "#version 410 core                                                                 \n"
            "                                                                                  \n"
            "layout (triangles, equal_spacing, cw) in;                                         \n"
            "                                                                                  \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"
        };
        //fragment shader 소스
        static const char * fragment_shader_source[] = {
                   "#version 420 core                                                 \n"
            "                                                                  \n"
            "out vec4 color;                                                   \n"
            "                                                                  \n"
            "void main(void)                                                   \n"
            "{                                                                 \n"
            "    color = vec4(1.0, 1.0, 1.0, 1.0);                             \n"
            "}                                                                 \n"
        };
        //버텍스 쉐이더를 생성하고 컴파일한다.
        vertex_shader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
        glCompileShader(vertex_shader);

        GLuint tcs = glCreateShader(GL_TESS_CONTROL_SHADER);
        glShaderSource(tcs, 1, tcs_source, NULL);
        glCompileShader(tcs);

        GLuint tes = glCreateShader(GL_TESS_EVALUATION_SHADER);
        glShaderSource(tes, 1, tes_source, NULL);
        glCompileShader(tes);

        //프래그먼트 쉐이더를 생성하고 컴파일하낟.
        fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
        glCompileShader(fragment_shader);

        //프로그램을 생성하고 쉐이더를 어태치(attach,부착)시키고 링크한다.
        program = glCreateProgram();
        glAttachShader(program, vertex_shader);
        glAttachShader(program, tcs);
        glAttachShader(program, tes);
        glAttachShader(program, fragment_shader);
        glLinkProgram(program);

        glGenVertexArrays(1, &vertex_array_object);
        glBindVertexArray(vertex_array_object);

        //이제 프로그램이 쉐이더를 소유하므로 쉐이더를 삭제한다
        glDeleteShader(vertex_shader);
        glDeleteShader(fragment_shader);

        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

        return program;


    }
};

DECLARE_MAIN(simpleclear_app)

 

728x90
반응형

댓글