ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Python으로 배우는 Modern OpenGL - 3. 사각형 그리기( Element Buffer Object)
    OpenGL/Python으로 배우는 OpenGL 2018. 12. 16. 23:28


    PyOpenGL과 GLFW를 사용하여 사각형을 그려보는 Modern OpenGL 예제입니다.



    다음 깃허브의 코드를 바탕으로 강좌를 진행하고 있습니다.

    https://github.com/totex/PyOpenGL_tutorials



    Python으로 배우는 Modern OpenGL - 1. 개발환경 만들기

    https://webnautes.tistory.com/1271


    Python으로 배우는 Modern OpenGL - 2. 삼각형 그리기(Vertex Buffer Object)

    https://webnautes.tistory.com/1272




    이전 포스팅과 겹치는 부분을 제외하고 설명합니다.


    사각형을 그리려면 삼각형을 2번 그려야 합니다. 그러면 같은 버텍스를 두 번 정의해야 하는 문제가 생깁니다.

    복잡한 모델을 이 방식으로 화면에 보여줄 경우에는 메모리 낭비와 성능 저하가 생길 수 있습니다.



    이 문제를 해결하기 위해 EBO(Element Buffer Object)를 사용합니다.

    EBO를 사용하면 버텍스에 인덱스를 부여하여 렌더링시 재사용할 수 있도록 해줍니다.




    4개의 vertex에 대한 vertex 데이터만 배열에 저장합니다.  

    추가로 vertex 데이터에 대한 인덱스를 저장하는 elements 배열을 선언하고, 6개의 인덱스를 정의합니다.  두 개의 삼각형을 그릴 때, vertices 배열에서 몇번째 vertex를 이용할지를 정수로 적어주는 것입니다.


       #            positions    colors
       quad = [   -0.5,  0.5, 0.0, 1.0, 0.0, 0.0,  # Top-left      -- 인덱스 0
                   0.5,  0.5, 0.0, 0.0, 1.0, 0.0,  # Top-right     -- 인덱스 1
                   0.5, -0.5, 0.0, 0.0, 0.0, 1.0,  # Bottom-right  -- 인덱스 2
                  -0.5, -0.5, 0.0, 1.0, 1.0, 1.0]  # Bottom-left   -- 인덱스 3

       quad = numpy.array(quad, dtype = numpy.float32)


       indices = [0, 1, 2,
                  2, 3, 0]

       indices = numpy.array(indices, dtype= numpy.uint32)





    VBO를 생성하여 quad에 있는 버텍스 데이터  96바이트( = 4바이트 x 24 )를 GPU 메모리에 복사합니다.


       VBO = glGenBuffers(1)
       glBindBuffer(GL_ARRAY_BUFFER, VBO)
       glBufferData(GL_ARRAY_BUFFER, 96, quad, GL_STATIC_DRAW)




    EBO를 생성하여 vertex 데이터에 대한 인덱스인 indices 배열을 복사합니다.

       EBO = glGenBuffers(1)
       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
       glBufferData(GL_ELEMENT_ARRAY_BUFFER, 24, indices, GL_STATIC_DRAW)




    인덱스를 사용하여  삼각형 2개를 그리기위해서 glDrawArrays 함수 대신에  glDrawElements 함수를 사용합니다.


           glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)




    실행시켜 보면 다음 처럼 사각형이 그려집니다.





    포스팅에 사용한 코드입니다.


    import glfw
    from OpenGL.GL import *
    import OpenGL.GL.shaders as shaders
    import numpy


    def main():

       if not glfw.init():
           return

       window = glfw.create_window(800, 600, "My OpenGL window", None, None)

       if not window:
           glfw.terminate()
           return

       glfw.make_context_current(window)


       #            positions    colors
       quad = [   -0.5,  0.5, 0.0, 1.0, 0.0, 0.0,  # Top-left
                   0.5,  0.5, 0.0, 0.0, 1.0, 0.0,  # Top-right
                   0.5, -0.5, 0.0, 0.0, 0.0, 1.0,  # Bottom-right
                  -0.5, -0.5, 0.0, 1.0, 1.0, 1.0]  # Bottom-left

       quad = numpy.array(quad, dtype = numpy.float32)


       indices = [0, 1, 2,
                  2, 3, 0]

       indices = numpy.array(indices, dtype= numpy.uint32)


       print(quad.itemsize * quad.size)

       vertex_shader_source = """
       #version 330
       in vec3 position;
       in vec3 color;

       out vec3 newColor;
       void main()
       {
           gl_Position = vec4(position, 1.0f);
           newColor = color;
       }
       """

       fragment_shader_source = """
       #version 330
       in vec3 newColor;

       out vec4 outColor;
       void main()
       {
           outColor = vec4(newColor, 1.0f);
       }
       """

       vertex_shader = shaders.compileShader(vertex_shader_source, GL_VERTEX_SHADER)
       fragment_shader = shaders.compileShader(fragment_shader_source, GL_FRAGMENT_SHADER)
       shader = shaders.compileProgram(vertex_shader, fragment_shader)


       VBO = glGenBuffers(1)
       glBindBuffer(GL_ARRAY_BUFFER, VBO)
       glBufferData(GL_ARRAY_BUFFER, 96, quad, GL_STATIC_DRAW)

       EBO = glGenBuffers(1)
       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
       glBufferData(GL_ELEMENT_ARRAY_BUFFER, 24, indices, GL_STATIC_DRAW)

       position = glGetAttribLocation(shader, "position")
       glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(0))
       glEnableVertexAttribArray(position)

       color = glGetAttribLocation(shader, "color")
       glVertexAttribPointer(color, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(12))
       glEnableVertexAttribArray(color)

       glUseProgram(shader)

       glClearColor(0, 0, 0, 0)

       while not glfw.window_should_close(window):
           glfw.poll_events()

           glClear(GL_COLOR_BUFFER_BIT)

           glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)

           glfw.swap_buffers(window)

       glfw.terminate()


    if __name__ == "__main__":
       main()



    포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
    댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

    여러분의 응원으로 좋은 컨텐츠가 만들어집니다. 지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다. 감사합니다 : )

    유튜브 구독하기


    댓글 0

Designed by Tistory.