본문 바로가기

Library/Computer Graphics

OpenGL Fixed Rendering Pipeline

대다수의 OpenGL 구현은 OpenGL 렌더링 파이프라인(OpenGL rendering pipeline)이라고 부르는 일련의 처리 단계를 따른다. OpenGL을 반드시 다음과 같은 렌더링 파이프라인대로 구현해야 하는 것은 아니다. OpenGL은 구현만을 지칭하는 것은 아니며, ARB가 평가하는 OpenGL 스펙을 모두 만족한다면 OpenGL 구현으로 인정받을 수 있다. 그래서 OpenGL은 공식적인 구현 외에도 Mesa3D와 같은 공개 OpenGL 구현도 존재한다. Mesa3D는 공식적인 OpenGL 구현은 아닌데, 이것은 라이센스 문제 때문이다. Mesa3D는 X.org와 같은 프로젝트에서도 중요하게 사용되고 있다.






OpenGL 파이프라인에서 정점, 선, 폴리곤과 같은 기하 데이터는 평가자(Evaluator)와 정점 연산(Vertex Operation)을 거치지만, 픽셀, 이미지, 텍스처와 같은 픽셀 데이터는 이와 다른 경로를 거친다. 이들 데이터는 래스터화, 프래그먼트 연산에서 만나고, 최종적으로 프레임버퍼에 기록된다. OpenGL은 상태 머신(state machine)으로 간주할 수 있으며, 이것은 특정한 상태나 모드를 설정하면 이를 변경하기 전까지 그 상태로 계속해서 동작한다는 의미이다(GDI와 비슷하다). OpenGL은 대부분의 상태와 정보를 glGet*(), glIsEnable() 함수를 통해 얻을 수 있으며, 프레임버퍼에 있는 값까지 glReadPixels() 함수를 통해 가져올 수 있다.

Display List : 디스플레이 리스트는 차후의 실행을 위한, OpenGL 명령어들이 저장되어 있는 집합이다. 기하 정보, 픽셀 정보와 같은 모든 정보가 저장될 수 있고, 여기에 저장된 정보는 캐시가 적용될 수 있기 때문에 성능을 향상시킬 수도 있다.

Evaluator : 모든 기하 프리미티브들은 결국 정점으로 표현된다. 매개변수 곡선이나 곡면은 처음에는 기저 함수(basis function)라고 불리는 다항 함수와 제어점(control point)들로 표현된다. 평가자(evaluator)를 사용하면 이러한 제어점으로부터 곡면을 표현하는데 사용되는 정점들을 구할 수 있다. 이때 다항식 매핑(polynomial mapping)이라는 기법을 사용하면, 제어점으로부터 표면 법선(surface normal), 텍스처 좌표, 컬러, 공간 좌표 등을 얻을 수 있다.

Vertex Operation : 정점들을 프리미티브로 변환한다. 3D 공간의 한 지점을 나타내던 공간 좌표는 스크린 좌표의 한 지점으로 투영된다. 고급 기능들이 활성화되어 있다면, 이 단계는 더욱 복잡해진다. 예를 들어, 만약 조명(lighting)이 활성화되어 있다면, 변환된 정점 정보 중 조명과 관련된 정보를 이용하여 컬러값을 생성하는 라이팅 연산이 수행된다.

Primitive Assembly : 이 단계에서 주된 부분은 클리핑(clipping)이다. 정점 연산(Vertex Operation)이 이루어진 뒤, 프리미티브 요소들은 투영(projection)에 의해 다시 한번 더 변환되고, 클리핑이 일어난다. 이 단계를 거치고 나면, 컬러, 깊이, 텍스처 좌표, 래스터화 단계를 위한 가이드라인 등에 따라 변환 및 클리핑된 정점들도 구성된 완전한 형태의 기하 프리미티브가 생성된다.

Pixel Transfer Operation : 픽셀 데이터는 OpenGL 렌더링 파이프라인에서 기하 데이터와 다른 경로를 따라 처리되며, 먼저 시스템 메모리에 특정한 포맷의 배열로 저장된 픽셀들을 읽는다. 이 데이터는 스케일링(scaling), 가중치(basis) 적용과 같은 연산이 적용된다. 이 과정을 Pixel Transfer Operation이라 하는데, 이 결과는 텍스처 메모리에 저장될 수도 있고, 바로 프래그먼트(fragment)에 래스터화될 수도 있다.

Rasterization : 래스터화 단계에서는, 기하 데이터와 픽셀 데이터를 모두 프래그먼트로 변환한다. 각각의 프래그먼트들은 색상, 깊이, 선의 두께, 점의 두께, 안티-앨리어싱 따위를 포함하는 배열이다. 각각의 프래그먼트 하나는 프레임버퍼의 한 픽셀에 대응된다.

Fragment Operation : 값들이 실제로 프레임버퍼에 저장되기 전에 프래그먼트 연산을 수행하여 특정한 프래그먼트들을 변경하거나 제거한다. 즉, 프래그먼트 연산은 프레임버퍼로 픽셀이 기록되기 전의 마지막 단계이다. 하나의 텍스처 요소는 텍스처 메모리에서 생성되며, 각각의 프래그먼트에 적용된다. 안개 효과(fog calculation)가 적용된 뒤에, Scissor Test - Alpha Test - Stencil Test - Depth Test의 순서대로 프래그먼트 연산이 이루어진다. 마지막으로 블렌딩(blending), 디더링(dithering), 각각의 비트 마스크에 의한 논리 연산이 이루어진 뒤에 프레임버퍼에 기록될 실제 픽셀 값이 결정된다.

 

Reference
Dave Shreiner, Mason Woo, Jackie Neider, Tom Davis, OpenGL programming guide : The official guide to learning OpenGL, 4th edition, Pearson Education

http://www.songho.ca/opengl/gl_pipeline.html

 

덧글(Feb 13, 2013): 여기서 설명하고 있는 OpenGL의 렌더링 파이프라인은 OpenGL 2.0 이전의 고정 파이프 라인이다. 쉐이더를 사용하고 있는 현대 OpenGL의 렌더링 파이프라인은 크게 다르다.