래스터화
도형을 픽셀 격자로 옮기는 절차입니다. 넣는 것은 화면 위에 자리를 잡은 도형 하나입니다. 나오는 것은 그 도형이 덮은 격자 칸들이고, 칸마다 색과 깊이 같은 값이 붙습니다.
상세
래스터화는 프리미티브 하나를 2차원 이미지로 바꾸는 절차입니다. 이 이미지의 각 점은 색과 깊이 같은 정보를 담습니다. 프리미티브는 그리기의 기본 단위입니다. 점과 선분과 삼각형이 그것입니다.
절차는 윈도 좌표계의 정수 격자에서 어느 칸이 프리미티브에 점유되는지 정하는 일로 시작합니다. 그리고 그렇게 골라진 칸마다 깊이 값을 하나씩 매깁니다.
격자 칸 하나에 (x, y) 윈도 좌표와 z 깊이, 그리고 뒤따르는 프래그먼트 셰이더가 더할 수 있는 연관 데이터가 붙은 것을 프래그먼트라고 부릅니다. 프래그먼트의 자리는 왼쪽 아래 모서리로 정해집니다. 그 모서리는 정수 격자 좌표 위에 놓입니다. 래스터화 규칙은 프래그먼트의 중심도 가리킵니다. 중심은 왼쪽 아래 모서리에서 (1/2, 1/2) 만큼 어긋난 자리라 반정수 좌표에 놓입니다.
프래그먼트가 실제로 정사각형일 필요는 없습니다. 래스터화 규칙은 프래그먼트의 종횡비에 영향받지 않습니다. 다만 정사각형이 아닌 격자로 표시하면 래스터화된 점과 선분이 한 방향으로 더 두꺼워 보입니다. 규칙은 프래그먼트를 정사각형으로 가정합니다. 그러면 안티에일리어싱과 텍스처링이 단순해집니다.
래스터화가 끝나면 프래그먼트는 초기 프래그먼트별 테스트를 거칩니다. 그 테스트가 프래그먼트를 고치거나 버릴 수 있습니다. 살아남은 프래그먼트를 프래그먼트 셰이더가 처리합니다. 여기서부터는 래스터화 밖입니다.
복잡도
n 은 프리미티브가 덮은 격자 칸 수입니다. 곧 만들어지는 프래그먼트 수입니다. m 은 그 판정을 받는 후보 칸 수입니다.
| 연산 | 평균 | 최악 | 왜 그런가 |
|---|---|---|---|
| 프리미티브 셋업 | O(1) | 같습니다 | 정점 수가 프리미티브 종류로 고정돼 있습니다. 삼각형은 셋, 선분은 둘, 점은 하나입니다 |
| 커버리지 판정 | O(m) | 화면 격자 칸 수 | 점 샘플링은 후보 칸마다 그 중심이 도형 안에 드는지 한 번씩 묻습니다. 프리미티브 하나가 화면을 다 덮으면 후보가 화면 전체입니다 |
| 프래그먼트 생성 | O(n) | O(n) | 덮은 칸마다 하나씩 나옵니다. 출력 크기에 그대로 비례합니다 |
| 속성 보간 | 프래그먼트마다 O(1) | 같습니다 | 무게중심 좌표 셋으로 값 하나를 계산합니다. 보간할 속성 수만큼 되풀이합니다 |
비용을 지배하는 것은 정점 수가 아니라 덮은 면적입니다. 정점 셋짜리 삼각형 하나가 화면을 가득 덮으면 화면 칸 수만큼 프래그먼트가 나옵니다. 몇 픽셀만 차지하는 삼각형은 정점 수가 같아도 프래그먼트를 몇 개만 냅니다. 그래서 프리미티브 개수를 세는 것으로는 비용이 잡히지 않습니다.
최악은 겹침에서 옵니다. 여러 프리미티브가 같은 칸을 거듭 덮으면 총 프래그먼트 수가 화면 칸 수를 넘어갑니다. 격자는 화면 크기로 고정입니다. 그 위를 덮는 횟수에는 상한이 없습니다.
픽셀 하나에 샘플을 여럿 두는 방식에서는 커버리지 판정이 샘플 수만큼 되풀이됩니다.
공간은 프리미티브마다 상수입니다. 셋업 값과 보간 계수만 들고 있으면 됩니다. 격자 자체는 화면 크기로 정해져 있어 프리미티브가 늘어도 커지지 않습니다.
예시
VkPipelineRasterizationStateCreateInfo
Vulkan 명세는 래스터화에 영향을 주는 요소로 이 구조체와 멀티샘플 상태 구조체를 듭니다.
typedef struct VkPipelineRasterizationStateCreateInfo {
VkStructureType sType;
const void* pNext;
VkPipelineRasterizationStateCreateFlags flags;
VkBool32 depthClampEnable;
VkBool32 rasterizerDiscardEnable;
VkPolygonMode polygonMode;
VkCullModeFlags cullMode;
VkFrontFace frontFace;
VkBool32 depthBiasEnable;
float depthBiasConstantFactor;
float depthBiasClamp;
float depthBiasSlopeFactor;
float lineWidth;
} VkPipelineRasterizationStateCreateInfo;
rasterizerDiscardEnable 은 프리미티브를 래스터화 단계 직전에 버릴지 정합니다. polygonMode
는 삼각형 렌더링 모드입니다. cullMode 는 프리미티브 컬링에 쓰는 삼각형 앞뒷면 방향입니다.
polygonMode 에는 조건이 붙습니다. fillModeNonSolid 기능이 켜져 있지 않으면 polygonMode
는 VK_POLYGON_MODE_FILL 이거나 VK_POLYGON_MODE_FILL_RECTANGLE_NV 여야 합니다.
Direct3D 11 의 래스터라이저 단계
Microsoft 공식 문서는 래스터화 단계가 도형이나 프리미티브로 이루어진 벡터 정보를 픽셀로 이루어진 래스터 이미지로 바꾼다고 적습니다. 실시간 3차원 그래픽스를 표시하려는 목적입니다. 같은 문서는 래스터라이저 단계가 프리미티브에 덮인 픽셀마다 픽셀 셰이더를 한 번씩 부른다고 적습니다. 널 셰이더를 지정해 셰이더를 안 돌리는 것도 가능합니다.
glPolygonMode
OpenGL(Open Graphics Library) 4 레퍼런스가 적는 호출입니다. 폴리곤을 래스터화할 때 어떻게 해석할지를 정합니다.
void glPolygonMode(GLenum face, GLenum mode);
face 는 앞면과 뒷면 폴리곤을 함께 가리키는 GL_FRONT_AND_BACK 이어야 합니다. mode 는
폴리곤이 어떻게 래스터화될지를 정합니다. 받는 값은 GL_POINT 와 GL_LINE 과 GL_FILL
셋입니다. 초기값은 앞뒷면 모두 GL_FILL 입니다. GL_POINT 는 경계 에지의 시작으로 표시된
폴리곤 정점을 점으로 그립니다. GL_LINE 은 폴리곤의 경계 에지를 선분으로 그립니다.
GL_FILL 은 폴리곤 내부를 채웁니다.
동작
flowchart TD
A[프리미티브] --> B[정점의 윈도 좌표로 2차원 투영]
B --> C{프래그먼트 중심이 안에 드나}
C -- 아니오 --> D[만들지 않는다]
C -- 예 --> E[격자 칸에 깊이 값을 매긴다]
E --> F[무게중심 좌표로 속성을 보간한다]
F --> G[프래그먼트]
폴리곤 래스터화가 어느 프래그먼트를 낼지 정하는 규칙을 점 샘플링이라고 부릅니다. 먼저 폴리곤 정점의 x·y 윈도 좌표를 취해 2차원 투영을 만듭니다. 이 폴리곤 안쪽에 놓인 프래그먼트 중심이 래스터화의 결과물이 됩니다.
중심이 폴리곤 에지 위에 놓인 프래그먼트는 따로 다룹니다. 두 폴리곤이 끝점이 같은 공통 에지를 사이에 두고 양옆에 있고 그 에지 위에 프래그먼트 중심이 놓였다면, 두 폴리곤 중 정확히 하나만 그 프래그먼트를 만들어야 합니다. 같은 칸을 둘이 만들거나 아무도 안 만드는 일을 막는 규칙입니다.
선분에 어느 프래그먼트가 나올지는 이상적으로는 다이아몬드 이탈 규칙이 정합니다. 윈도 좌표 (xf, yf) 에 중심을 둔 프래그먼트마다 네 개의 반평면이 교차하는 마름모꼴 영역을 정의합니다.
Rf = { (x, y) | |x - xf| + |y - yf| < 1/2 }
pa 에서 시작해 pb 에서 끝나는 선분은 그 선분이 Rf 와 만나는 프래그먼트를 만들어 냅니다. pb 가 Rf 안에 들어 있는 경우는 예외입니다. pa 와 pb 가 프래그먼트 중심 위에 놓이면 이 이상적인 규정은 브레젠험 알고리즘으로 줄어듭니다. 한 가지만 다릅니다. 여기서 나오는 선은 반열림이라서 pb 에 해당하는 마지막 프래그먼트를 그리지 않습니다. 그래서 이어진 선분을 여러 개 래스터화할 때 공유하는 끝점이 두 번이 아니라 한 번만 나옵니다.
프래그먼트가 정해지면 속성값을 채웁니다. 삼각형에는 무게중심 좌표를 정의합니다. 무게중심 좌표는 각각 [0, 1] 범위에 있고 합이 1 인 세 수 a·b·c 입니다. 삼각형을 래스터화해서 나온 프래그먼트에서 어떤 데이터의 값 f 는 이렇게 정해집니다.
f = (a*fa/wa + b*fb/wb + c*fc/wc) / (a/wa + b/wb + c/wc)
wa·wb·wc 는 각 정점의 클립 w 좌표입니다. a·b·c 는 그 데이터를 만들어 낼 프래그먼트의 무게중심 좌표입니다. 프래그먼트에 딸린 데이터는 프래그먼트 중심에서 샘플링해야 합니다. 다만 폴리곤의 깊이 값은 다른 식으로 보간합니다.
z = a*za + b*zb + c*zc
za·zb·zc 는 각 정점의 깊이 값입니다. 깊이만 원근 나눗셈 없이 선형으로 섞는 것입니다.
관련 항목
이것 다음에 오는 처리 단계
프래그먼트 · 프래그먼트별 테스트 · 깊이 테스트 · 프래그먼트 셰이더 · 픽셀 셰이더 · 셰이더 · 프레임버퍼
이것 앞에 오는 처리 단계
이것을 제어하는 설정값
뎁스 바이어스 · 폴리곤 모드 · 컬링
이것이 커버리지와 값을 정하는 규칙·좌표계
점 샘플링 · 다이아몬드 이탈 규칙 · 브레젠험 알고리즘 · 무게중심 좌표 · 윈도 좌표
이것 위에 얹히는 렌더링 기법
이것이 속하는 상위 분류
그래픽스 파이프라인 · 렌더링 · 그래픽스
이것을 실제로 구현·채택한 제품
Vulkan · OpenGL(Open Graphics Library, 오픈 그래픽스 라이브러리) · Direct3D · Microsoft
이것과 겨루는 렌더링 방식
광선 추적
다른 이름: Rasterization · 래스터라이제이션