
사진 중 파란색으로 표시된 Vertex Shader, Geometry Shader, Fragment Shader는 개발자가 기존 기본 셰이더를 대체하기 위해 자체 셰이더를 GLSL로 작성할 수 있다. 이를 통해 특정 부분에 대해 훨씬 세밀한 제어 + CPU 절약이 가능하다.
보통 Vertex Shader와 Fragment Shader를 작성한다.
첫번째로, Vertex Data[]를 입력한다. Vertex Data[]는 우리가 그리고 싶은 도형의 정점 데이터를 의미한다. 정점 데이터는 정점들의 집합으로 이루어져 있다.
이러한 좌표 정보는 VBO(Vertex Buffer Object)에 저장되어 셰이더에게 전달된다.
Vertex Shader는 단일 정점을 입력으로 받는다. 주요 목적은 3D 좌표를 다른 3D 좌표로 변환하는 것인데, 이것은 나중에 설명해준다하고 안 알려줬다.. 공부하다보면 자연스레 배울 거라 생각한다. (아마 내 추측으로는 여러 좌표계에 따른 혼란이 있기 때문에 이것을 하나로 계산하는 게 아닐까? 싶다)
Vertex Shader를 통해 정점 속성에 대한 기본적인 처리를 수행할 수 있다.
Vertex Shader의 출력은 선택적으로 Geometry Shader로 전달된다. Geometry Shader는 하나의 primitive를 이루는 정점들의 집합을 입력으로 받으며, 새로운 정점을 생성해서 다른 도형을 만들어낼 수 있다.
OpenGL이 이 좌표와 색상 데이터로 무엇을 그려야 하는지 알기 위해서는, 어떤 형태로 렌더링할 것인지 힌트를 줘야 한다.
이런 힌트를 Primitive라고 하며, 드로우 함수 호출 시 함께 전달된다.
대표적인 프리미티브에는 GL_POINTS, GL_TRIANGLES, GL_LINE_STRIP 등이 있다.
Shape Assembly 단계는 하나 이상의 프리미티브를 형성하는 정점(또는 기하학) 셰이더에서 모든 정점(GL_POINTS를 선택한 경우 정점)을 입력으로 받아 주어진 primitive 형태로 모든 점들을 조립한다.
Shape Assembly 단계의 출력은 Rasterization 단계로 전달되어, primitive를 최종 화면의 해당 픽셀에 매핑하고, 그 결과로 Fragment Shader가 사용할 Fragment이 생성된다. Fragment는 OpenGL이 단일 픽셀을 렌더링하는 데 필요한 모든 데이터이다.
Fragment Shader가 실행되기 전에 클리핑이 수행되는데, 클리핑이란 시야 밖에 있는 모든 조각을 삭제하여 성능을 향상시키는 것이다.
Fragment Shader의 주요 목적은 픽셀의 최종 색상을 계산하는 것이며, 이는 일반적으로 고급 OpenGL 효과가 발생하는 단계이다. 보통 Fragment Shader는 3D 장면에 대한 데이터를 포함하고 있으며, 이를 사용하여 최종 픽셀 색상(e.g. 조명, 그림자, 빛의 색상 등)을 계산할 수 있다.
모든 해당 색상 값이 결정된 후, 최종 객체는 Tests and Blending 단계를 거친다. 이 단계에서는 depth test를 실행한다. 또한 알파 값(불투명도)을 확인하고 그에 따라 객체를 블렌딩한다. 따라서 픽셀 출력 색상이 Fragment Shader에서 계산되더라도, 여러 삼각형을 렌더링할 때 최종 픽셀 색상이 전혀 다를 수 있다.
| 단계 (Stage) | 입력 | 핵심 역할 | 출력 |
|---|---|---|---|
| Vertex Shader | 개별 정점 (Vertex) | 좌표 변환 (MVP), 정점 속성 계산 | 변환된 정점 |
| Shape Assembly | 정점들 + Primitive 힌트 | 정점들을 연결하여 도형(삼각형 등) 구성 | Primitives |
| Rasterization | 도형 (Primitives) | 도형을 픽셀 단위(Fragment)로 분해 | Fragments |
| Fragment Shader | Fragment | 최종 색상 결정 (조명 계산, 텍스처 적용) | 픽셀 색상 데이터 |
| Tests and Blending | 픽셀 색상 데이터 | 깊이 테스트, 스텐실 테스트, 알파 블렌딩(투명도 처리) | 최종 화면 (Frame Buffer) |
(Thin Matrix에서는 Vertex Shader의 출력값이 Freagment Shader의 입력값이라고 했는데, 자세히 들여다보면 위와 같은 과정을 거치고 Fragment Shader의 입력값으로 들어가는 것 같다.)
GPU에는 기본 vertex shader와 fragment shader가 없기 때문에 현대 OpenGL에서는 최소한 자체적인 vertex shader와 fragment shader를 정의해야 한다.
thinmatrix 2강에서 배경만 채워지고 삼각형이 안 그려져서 좌절했었는데 이런 이유였다. 자바 코드를 부족한 실력으로 C++로 전환하여 작성하였기 때문에 어느 부분이 잘못되었는지 난감했었다.. 또한 학부 강의에서는 실무보다 개념을 위주로 배웠기 때문에 Fixed Function Pipeline을 사용해서 이런 것들을 신경쓰지 않아도 됐었기 때문에 문제를 찾기 더 힘들었다.. 왕규(챗지피티)와 흠두(제미나이)가 있고, learnopengl.com이 있었다 ㅎㅎ
자세한 삼각형 그리기 구현과 앞서 말했던 VBO(+VAO)는 따로 게시물로 작성해보도록 하겠다.