지난 장에서 윈도우를 생성하여 화면에 색을 칠했습니다. 이제 간단한 도형을 그려보고 싶습니다. 하지만 그 전에 알고 넘어가야할 것이 있습니다.
화면에 원하는 물체들을 그리기 위해서는 먼저 렌더링 파이프라인에 대한 전반적인 이해가 필요합니다. 물체를 어떤 형태로 저장하고 각 파이프라인을 거치면서 어떻게 변환되고, 왜 변환하는지 알아야 그래픽스 공부를 더 즐겁게 할 수 있습니다.
위 그림은 OpenGL ES 3.0의 렌더링 파이프라인입니다. 모든 과정을 자세히 다루지는 않고 큰 흐름을 파악할 정도로만 정리를 하겠습니다. 필요한 부분은 다음에 별도의 장에서 이야기 하겠습니다.
렌더링하고 싶은 물체의 정점들을 렌더링 파이프라인에 전달하는 것이 렌더링 파이프라인의 시작입니다. 정점들을 Vertex Buffer와 Vertex Array에 복사하여 렌더링 파이프라인으로 보낼 수 있습니다.
버텍스 셰이더는 렌더링 파이프라인에서 프로그래밍 가능한 단계 중 하나입니다. 버텍스 셰이더는 glsl라는 언어를 사용하여 작성합니다. 버텍스 셰이더에서는 위의 버텍스 버퍼, 버텍스 어레이 단계에서 보낸 물체의 정점들을 받아서 여러가지 작업들을 수행할 수 있습니다. 가장 핵심적인 작업은 좌표 변환 작업입니다. Vertex Buffer에 저장된 정점들은 각 물체의 로컬좌표계 상에 존재합니다. 그러므로 이 정점들에 순서대로 모델행렬, 뷰행렬, 프로젝션행렬을 곱해서 좌표계를 클립 좌표계로 변환시킵니다. 이렇게 하면 해당 카메라 시야의 뷰프러스텀에 물체를 위치시킬 수 있습니다.
프리미티브 어셈블리 단계에서는 이전 단계에서 클립 좌표계로 변환된 정점들을 바탕으로 프리미티브(lines, points, triangles)를 생성합니다. 그리고 생성된 프리미티브들은 뷰프러스텀을 경계로 클리핑됩니다. 클리핑 단계에서 뷰프러스텀 밖에 존재하던 프리미티브 영역은 제거되고 뷰프러스텀 안쪽을 경계로 새로운 프리미티브를 생성합니다. 그 다음, 버텍스 셰이더에서 프로젝션 변환을 통해 생성된 동차좌표 w성분으로 x, y, z 성분을 나누어주는 원근분할을 수행하여 NDC로 변환합니다. 마지막으로 viewport 변환을 수행하여 2차원 윈도우 좌표계로 변환합니다. viewport 변환 시 깊이 버퍼에 z 값이 저장됩니다.
레스터라이제이션 단계에서는 프리미티브를 프레그먼트로 레스터화시킵니다. 프레그먼트는 출력 프레임 버퍼에서 픽셀에 대한 최종 데이터를 계산하는데 사용되는 상태 집합입니다.
레스터라이제이션 단계에서 생성된 각 프레그먼트들은 프레그먼트 셰이더 단계에서 처리됩니다. 프레그먼트 셰이더는 버텍스 셰이더와 마찬가지로 프로그래밍 가능한 단계입니다. 프레그먼트 셰이더의 출력은 각 색상 버퍼에 쓰여지는 색상, 깊이값, 스텐실 값입니다. 프레그먼트 셰이더는 프레그먼트에 대한 스텐실 데이터를 설정할 수 없지만, 색상과 깊이값을 조작할 수 있습니다.
Per-Fragment Operations 단계는 프레그먼트 셰이더 단계에서 출력된 프레그먼트가 처리되고 결과 데이터가 다양한 버퍼에 기록되는 단계입니다. 프레임 버퍼의 해당 픽셀에 저장하기 전에 프레그먼트 셰이더에 의해 생성된 프레그먼트 색상을 수정할 수 있는 일련의 테스트 및 작업으로 구성됩니다. 테스트 중 하나라도 실패하면 프레그먼트가 삭제됩니다.
최종적인 렌더링 결과가 프레임 버퍼에 저장되고 윈도우에 출력할 때 프레임 버퍼를 불러들입니다.