OpenGL 그래픽 파이프라인 [Learn OpenGL 쉬운 번역]

728x90
반응형
※ 본 포스팅은 learnopengl.com을 번역 및 가감한 포스팅이며, learnopengl에서는 번역 작업 참여를 적극 장려하고 있습니다!
아래 링크에서 원문을 확인할 수 있습니다.

 

Hello Triangle

OpenGL은 3D 공간에 존재하는 개념을 2D 픽셀로 이루어진 화면에 그려내는데요. 그래서 3D 좌표를 화면에 맞게 2D로 변환해주어야합니다. 이는 graphics pipeline(그래픽 파이프라인)이라는 과정을 거치면서 이루어지는데요. 그래픽 파이프라인은 크게 두 부분으로 나뉘어집니다. 첫 번째 부분은 3D 좌표를 2D 좌표로 변환하고, 두 번째 부분은 2D 좌표를 실제 색상 픽셀로 변환합니다. 이번 포스팅에서에서는 그래픽 파이프라인을 설명하고, 활용하여 픽셀을 생성하는 방법을 알아봅시다.

 

그래픽 파이프라인은 3D 좌표와 변환정보를 받고 2D 화면에 띄울 픽셀로 변환합니다. 그래픽 파이프라인은 여러 단계로 나눌 수 있는데, 단게별로 이전 단계에서 출력된 결과를 입력하는 방식입니다. 각 단계마다 특수한 기능을 수행하도록 분리되어있어서 병렬적으로 실행할 수 있습니다.

이러한 병렬적인 성질이 있어서 그래픽 카드에는 수천 개 이상의 작은 코어들이 각각 그래픽 파이프라인에서 데이터를 처리합니다. 코어 하나하나는 파이프라인의 각 단계에서 GPU에서 실행되는 프로그램들을 각각 실행하는데, 이 프로그램을 shader(셰이더)라고 부릅니다.

 

셰이더는 개발자가 구성할 수 있는 부분도 있어서, 기본 셰이더를 직접 작성해서 변경할 수 있습니다. 파이프라인의 특정 부분에서 개발자가 원하는 대로 로직을 변경할 수 있겠죠. 또한 GPU에서 실행하는 로직이므로 CPU의 일을 덜어준다는 장점도 있습니다. OpenGL에서는 셰이딩 언어로 GLSL(OpenGL Shading Language)을 사용합니다.

 

아래 그림에 그래픽 파이프라인의 모든 단계가 간단히 나와있습니다. 이 중 파란색 단계가 개발자가 직접 셰이더를 통해 로직을 짤 수 있는 부분입니다.

그래픽 파이프라인은 정점 데이터를 렌더링 된 픽셀로 변환하는 여러 단계로 되어있는데, 파이프라인의 작동에 각 부분을 설명해봅시다. 

삼각형을 만들기 위해서는 입력으로 3D 좌표 세 개를 전달합니다. 이걸 Vertex Data라고 부르고, 정점 정보들을 말합니다. 정점(Vertex)는 3D좌표에 대한 데이터 형식인데, 이 데이터는 우리가 조정할 수 있는 속성(Attributes)입니다. 설명이 어려울 수 있는데, 간단하게 3D 좌표상의 위치와 색상 정보가 들어있는 구조로 이해하면 됩니다.

 

OpenGL이 좌표와 색상을 어떻게 처리하는지 데이터로 전달해야합니다. 이 데이터들을 어떻게 점으로 표현할지, 선으로 연결해서 삼각형을 만들어서 렌더링 할 지, 면을 표현할지를 결정할 필요가 있습니다.
이러한 정보들을 프리미티브(Primitives)라고 하고 OpenGL에서는 Draw 명령에 전달되는 정보입니다. 그 종류로 GL_POINTS, GL_TRIANGELS, GL_LINE_STRIP 등이 있습니다.

 

파이프라인의 첫 단계는 Vertex Shader(정점 셰이더)로, 하나의 정점을 입력 받습니다. 정점 셰이더에서는 3D 좌표를 다른 좌표로 변환하는 translation을 수행하고, vertex attribute에 대한 기본적인 처리를 합니다.

 

vertex shader의 출력은 Geometry Shader(지오메트리 셰이더)로 전달됩니다. 하지만 전달되지 않는 경우도 있습니다. geometry shader는 primitive를 구성하는 vertex들을 입력으로 받아서 새 vertex를 생성해서 새로운 primitive를 만들어서 다른 모양을 만드는 역할을 합니다.

그림에서 보는 것처럼 삼각형이라는 형태의 primitive 개념을 잡았습니다.

 

그림에서 shape assembly 라고 되어있는 primitive assembly stage(프리미티브 조립 단계)는 vertex shader나 geometry shader에서 전달받은 정점들을 입력으로 받습니다. (GL_POINTS 인 경우에는 정점 하나를 줍니다) 

받은 vertex들을 바탕으로 primitive를 조립해서 만듭니다. 그림에서는 두 삼각형이 생성되었죠.

 

primitive assembly stage에서 나온 결과는 다음 단계인 rasterization stage(래스터화 단계)로 전달됩니다. 여기서는 primitive를 출력해야하는 화면의 픽셀에 매핑해서 fragment라는 것을 생성합니다.

이걸 fragment shader에서 사용하는데, fragment shader 실행 전에 Clipping이라고 하여 화면 시야 밖에 있는 fragment 들은 삭제되어 최적화됩니다. 

 

Opengl에서 fragment는 픽셀 하나를 렌더링하기 위한 모든 데이터를 말합니다.

 

fragment shader는 마지막에 화면에 띄울 픽셀 색상을 계산해내는 것입니다. fragment shader에서 대부분의 OpenGL에서 하는 고급 기술들을 처리합니다. 3D 그래픽에서 색상과 관련된 처리, 예를 들어 조명, 그림자, 빛의 색상 등 계산을 합니다.

 

픽셀 색상을 결정하고 나서, 마지막으로 alpha testblending 단계라고 불리는 마지막 단계를 수행합니다. 여기서는 fragment의 depth와 stencil 값을 확인하고, 이를 통해서 fragment가 다른 객체보다 앞인지 뒤인지를 판단합니다. 그래서 보이지 않는 영역을 폐기할지를 경정하는 역할을 합니다. 

또 이 단계에서는 alpha(불투명도)를 확인하고, 이를 기반으로 객체를 blending합니다. blending 한다는 것은 앞의 물체가 투명하면 뒤에있는 사물이 흐릿하게 너머 보이는데 그런 현상을 표현한다는 뜻입니다. fragment shader에서 픽셀을 출력하는 색상이 계산되어도 여러 개의 object를 렌더링 할때는 이러한 점들 때문에 픽셀의 색이 달라질 수 있습니다.

 

이렇게 그래픽 파이프라인은 복잡합니다. 하지만 직접 구성할 수 있는 부분들이 있죠. 주로 vertex shader와 fragment shader를 코딩하게 될 것이고 geometry shader의 경우는 좀 더 필요한 경우 사용합니다. 그리고 그림에서 표현하지 않았지만 tessellation 단계와 transfrom feedback loop 단계도 있는데 나중에 보도록 합시다.

 

현대의 OpenGL에서는 최소 vertex shader와 fragment shader는 GPU에 기본적으로 없기 때문에 직접 정의해야합니다. 그래서 OpenGL을 배우려고 삼각형을 그리기까지만 해도 알아야할 지식이 많아 어려움을 많이들 느낍니다. 하지만 삼각형만 렌더링하면 정말 많은 산을 넘어간 것입니다. 

 

다음 포스팅에서 vertex input부터 시작합니다. 

728x90
반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유