반응형


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()



반응형

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

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

유튜브 구독하기


제가 쓴 책도 한번 검토해보세요.

+ Recent posts