ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Opengl 지오메트리 쉐이더(geometry shader, 기하 쉐이더)
    3D웹 프로그래밍/opengl 2020. 11. 19. 16:26
    728x90
    반응형

    지오메트리 쉐이더

     

    지오메트리 쉐이더는 버텍스 스테이지와 테셀레이션 스테이지의 다음단계이며, 개념적으로는 마지막 쉐이더 스테이지다.

    지오메트리 쉐이더는 프리미티브당 한 번 수행되며, 수행되는 프리미티브를 구성하는 모든 버텍스에 대한 입력 버텍스 데이터에 접근할수있다.

    또한 데이터 흐름의 양을 증가시키거나 감소시킬수있는 유일한 쉐이더 스테이지다.

     

    지오메트리는 EmitVertex()와 EndPrimitive()함수를통해 프리미티브 어셈블리 및 래스터라이제이션으로 보내는 버텍스를 명시적으로 생성할 수 있다.

     

    지오메트리 쉐이더의 다른 고유한 기능으로 파이프라인 중간에 프리미티브의 모드를 변경하는 기능이 있다.

    예를들면 삼각형들을 입력으로 하여 여러 점이나 선을 출력으로 만들어 낼수있다.

     

    예를들면

     

     static const char * gs_source[] =
            {
                "#version 410 core                                                                  \n"
                "                                                                                   \n"
                "layout (triangles) in;                                                             \n"
                "layout (points, max_vertices = 3) out;                                             \n"
                "                                                                                   \n"
                "void main(void)                                                                    \n"
                "{                                                                                  \n"
                "    int i;                                                                         \n"
                "                                                                                   \n"
                "    for (i = 0; i < gl_in.length(); i++)                                           \n"
                "    {                                                                              \n"
                "        gl_Position = gl_in[i].gl_Position;                                        \n"
                "        EmitVertex();                                                              \n"
                "    }                                                                              \n"
                "}                                                                                  \n"
            };

     

    위 코드는 버텍스를 확인할 수 있게 삼각형을 점으로 변환하는 또 하나의 간단한 통과 쉐이더를 만든것이다.

     

    첫번째 레이아웃으로 삼각형을 입력으로 받고 두번째 레이아웃지시어로 지오메트리 쉐이더가 점을 생성할 때 각 쉐이더가 생성하는 점의 최대 개수가 3이라는것을 Opengl에 알린다. main 함수에서 gl_in배열의 멤버를 루프로 돌면서 가져온뒤 gl_position에 넣고 EmitVertex()함수를 통해 점을 생성한다. 지오메트리 쉐이더는 쉐이더 종료시 자동적으로 EndPrimitive()를 호출한다. 수행결과는 세 버텍스가 생성되고 점으로 렌더링 되는것이다.

     

     

     

    다음은 전체 코드이다

     

    /*
     * 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);
    
            glPointSize(5.0f);
    
            //삼각형을 하나 그린다.
            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* gs_source[] =
            {
                "#version 410 core                                                                  \n"
                "                                                                                   \n"
                "layout (triangles) in;                                                             \n"
                "layout (points, max_vertices = 3) out;                                             \n"
                "                                                                                   \n"
                "void main(void)                                                                    \n"
                "{                                                                                  \n"
                "    int i;                                                                         \n"
                "                                                                                   \n"
                "    for (i = 0; i < gl_in.length(); i++)                                           \n"
                "    {                                                                              \n"
                "        gl_Position = gl_in[i].gl_Position;                                        \n"
                "        EmitVertex();                                                              \n"
                "    }                                                                              \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);
    
            GLuint gs = glCreateShader(GL_GEOMETRY_SHADER);
            glShaderSource(gs, 1, gs_source, NULL);
            glCompileShader(gs);
    
            //프래그먼트 쉐이더를 생성하고 컴파일하낟.
            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, gs);
            glAttachShader(program, fragment_shader);
            glLinkProgram(program);
    
            glGenVertexArrays(1, &vertex_array_object);
            glBindVertexArray(vertex_array_object);
    
            //이제 프로그램이 쉐이더를 소유하므로 쉐이더를 삭제한다
            glDeleteShader(vertex_shader);
            glDeleteShader(tcs);
            glDeleteShader(tes);
            glDeleteShader(gs);
            glDeleteShader(fragment_shader);
    
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    
            return program;
    
    
        }
    };
    
    DECLARE_MAIN(simpleclear_app)
    
    
    728x90
    반응형
Designed by Tistory.