정점 데이터 → 화면 픽셀로 변환되는 일련의 단계를 말한다.

CPU가 Draw Call 및 상태 설정 API를 호출하면
드라이버/런타임이 이를 GPU 명령으로 변환하여 Command Buffer에 기록한다.

GPU는 Command Buffer에 기록된 명령 스트림을 순차적으로 실행한다.

Group 893


Input Assembler(IA)

정점 데이터를 조립해서 삼각형 단위로 만들어 전달한다.
정점 데이터를 로드하고 정점 정보, 인덱스 정보로 삼각형을 구성한다.

GPU가 이해하는 정점 최소 조립 단위가 삼각형인 이유

Rasterizer는 어떤 픽셀을 실제로 그릴지 결정해야 한다.
모든 픽셀이 색, UV, normal, depth 등의 attribute 값을 가지고 있지 않다.
몇개의 정점에 값이 주어지면 그 값을 보간해 주변 픽셀에 사용한다.

삼각형 = 연속 영역
픽셀 = 이산 샘플
여러 삼각형과 겹칠 수 있음
삼각형 A → 픽셀 P 포함 → Fragment 생성
삼각형 B → 같은 픽셀 P 포함 → Fragment 생성
한 픽셀에 대해 여러 Fragment 생성 가능

더 가까운(Fragment depth가 작은) 것만 남김
겹치는 픽셀 → 가장 앞에 있는 삼각형의 보간값이 최종 값

3개의 점은 항상 하나의 평면을 정의할 수 있다.
4개 이상의 점은 동일 평면이 존재하지 않을 수 있음

내부 판별이 쉬운 삼각형(Primitive)을 기준으로 각 픽셀이 삼각형 내부에 포함되는지 판단한다.
삼각형 내부 판별은 Edge Function과 Barycentric Coordinate를 사용하여 효율적으로 처리할 수 있다.
20230519013952

한 점 P가 선분(또는 삼각형의 변)의 어느 쪽에 있는지 판단하는 함수 - 선형 함수 (Linear) - 곱셈/덧셈만 사용 - 분기 없이 계산 가능 - GPU에 적합

$A(x_1, y_1), B(x_2, y_2), P(x, y)$일 때
$E_{AB}(P) = (x - x_1)(y_2 - y_1) - (y - y_1)(x_2 - x_1)$

E > 0 → 한쪽 면
E < 0 → 반대쪽 면
E = 0 → 선 위

삼각형 내부 판별
$E_{AB}(P), E_{BC}(P), E_{CA}(P)$
세 값이 모두 같은 부호면 삼각형 내부

삼각형 내부의 점 P를
세 꼭짓점 A, B, C의 가중합으로 표현하는 좌표계

$
P = \alpha A + \beta B + \gamma C,\ \\
\alpha + \beta + \gamma = 1
$

α, β, γ = 각 정점의 영향도(weight)
α ≥ 0, β ≥ 0, γ ≥ 0 → 삼각형 내부

정점 속성이 f라면
$f(P) = \alpha f(A) + \beta f(B) + \gamma f(C)$

Barycentric의 가중치는 Edge Function의 정규화 결과다.
$\alpha = E_{BC}(P) / E_{BC}(A)$
$\beta = E_{CA}(P) / E_{CA}(B)$
$\gamma = E_{AB}(P) / E_{AB}(C)$

Edge Function은 점이 삼각형 내부인지 판단하고,
Barycentric Coordinate는 그 점이 삼각형 내에서
각 정점에 얼마나 가까운지를 나타내며,
이를 이용해 속성(색 UV, normal)을 보간한다.

20230519015037


Vertex Shader(VS)

  • 입력: 정점(Vertex) 데이터
  • 출력: 변환된 정점 (최소한 Clip Space 위치 포함)
  • 수행:
    • 좌표 변환
    • 정점 속성 처리 (Normal, UV 등)

VS에서

Local → World → View → Clip

까지 변환한다.

이후 GPU가 아래 과정 진행

→ NDC → Screen → Rasterization

좌표 공간

Local Space (Object Space)

오브젝트 기준 좌표
모델링 데이터가 정의된 좌표계
원점 (0,0,0)은 오브젝트 기준 위치

World Space

모든 오브젝트가 배치되는 공통 좌표계
Local → World 변환:

WorldPos = WorldMatrix * LocalPos

View Space (Camera Space)

카메라 기준 좌표계
카메라가 원점 (0,0,0)에 위치
변환:

ViewPos = ViewMatrix * WorldPos

Projection (투영변환) Matrix 적용

View Space → Clip Space

ClipPos = ProjectionMatrix * ViewPos

Projection Matrix에 의해 w 성분은 view-space z 값에 비례하도록 설정된다.
입력 정점은 (x, y, z, 1) 형태의 동차좌표로 확장된 후
행렬 곱을 통해 (x, y, z, w)로 변환된다.

실제 좌표 = (x/w, y/w, z/w)

(2, 4, 6, 2) → (1, 2, 3)
(1, 2, 3, 1) → (1, 2, 3)

Projection Matrix

$
P = \begin{bmatrix} \frac{1}{a\tan(\theta/2)} & 0 & 0 & 0 \\
0 & \frac{1}{\tan(\theta/2)} & 0 & 0 \\
0 & 0 & \frac{f}{f-n} & 1 \\
0 & 0 & \frac{-fn}{f-n} & 0
\end{bmatrix}
$

  • $\theta$: FOV
  • $a$: aspect ratio (width/height)
  • $n$: near plane
  • $f$: far plane

View Space 좌표 [x,y,z,1] → 투영 좌표

$x_c=\frac{x}{atan(θ/2)}$
$y_c=\frac{y}{atan(θ/2)}$

$z_c=z⋅\frac{f}{f−n}+1⋅\frac{−fn}{f−n}$
$z_c=\frac{fz−fn}{f−n}$

$w_c=z⋅1+1⋅0$
$w_c = z$

최종좌표:
[x,y,z,1] → $[\frac{x}{atan(θ/2)},\frac{y}{tan(θ/2)},\frac{f(z−n)}{f−n},z]$

원근감(Perspective)을 적용한다.
Perspective Projection : 원근감 존재, 멀수록 작게 보임
Orthographic Projection : 원근감 없음, 크기 유지


3차원 공간 좌표를 동차좌표로 바꾸는 이유

투영(원근)을 포함한 변환을 선형 연산으로 표현하기 위해 동차좌표를 사용했고,
그 결과 파이프라인 전체가 w 기준으로 정의되었다.
w는 단순 보조값이 아니라,
투영과 클리핑, 보간의 기준 값으로 사용된다.

Clip Space

Projection Matrix 적용 결과 공간
GPU가 Clipping을 수행하는 공간
변환:
ClipPos = ProjectionMatrix * ViewPos

Clipping

Frustum 내부는 렌더링 대상, 외부는 제거 대상이다.
이 외부 공간은 렌더링을 수행하지 않게 해 최적화한다.
이걸 Clipping이라고 한다.

Clipping은 Clip Space에서 수행되며,
경계를 넘는 Primitive는 잘려서 새로운 정점이 생성될 수 있다.

-w ≤ x,y,z ≤ w 조건으로 Primitive 일부/전체 제거 또는 분할

Tessellation

Primitive(삼각형/Patch)를 더 작은 Primitive로 분할하는 과정
입력으로 저해상도 메시로 들어오면 더 많은 정점/삼각형을 만든다.
기하 디테일 증가를 위해 사용한다.
GPU에서 동적으로 정점을 분할하고 변경한다.

저폴리곤으로 고폴리곤 구현 가능하다.
이 기능으로 LOD(Level of Detail)을 구현할 수 있다.

patch : Control Points 집합
Triangle Patch(3개)
Quad Patch (4개)

Tessellation은 Patch Primitive에서만 동작한다.

Hull Shader

입력으로 Patch가 들어오면 출력으로
Tessellation Factor, Control Points가 나온다.

얼마나 분할할지 결정하고 Edge/Inside Tessellation Level을 결정한다.

Tessellator

Tessellation Factor를 통해 새로 생성한 정점 좌표를 생성한다.

Domain Shader

Tessellator는 barycentric coordinate 또는 (u, v) 파라미터를 생성한다.

보간, 곡면 계산, 최종 정점 위치를 계산한다.


Geometry Shader

Primitive (점/선/삼각형) 단위 + VS/DS에서 온 정점 속성으로
정점을 추가/제거/변형하고 여러 Primitive으로 확장할 수 있다.


Rasterizer

Clip Space로 계산된 x, y, z, w값으로
Perspective Divde, Viewport Transform, Rasterization, 속성 보간이 이루어짐
삼각형 내부를 샘플(픽셀 후보, Fragment)로 생성

Perspective Divide

NDC (Normalized Device Coordinates) = (x/w, y/w, z/w)

$NDC=(\frac{x_c}{w_c},\frac{y_c}{w_c},\frac{z_c}{w_c})$
$$
x_{ndc}=\frac{x}{atan(θ/2)z} \\
y_{ndc}=\frac{y}{tan(θ/2)z} \\
z_{ndc}=\frac{f(z−n)}{(f−n)z} \\
$$

Viewport Transform

NDC → Screen Space (픽셀 좌표)

x, y → 픽셀 좌표
z → Depth 범위 [0, 1] (DirectX 기준)

$x_{screen}​=\frac{x_{ndc}​+1}{2}​⋅width+x_{viewport​}$
$y_{screen}​=\frac{1-y_{ndc}​}{2}⋅​height+y_{viewport​}$
$z_{screen}​=z_{ndc}⋅(z_{max}-z_{min})+z_{min}$

[-1, 1] 범위 → 실제 픽셀 영역으로 스케일 + 이동

속성 보간

Rasterizer는 (attribute / w)와 (1 / w)를 선형 보간한 후
Pixel Shader에서 attribute를 복원한다.


Pixel Shader

화면 위치, 보간된 속성, 텍스처 좌표를 통해
텍스처 샘플링, 조명 계산, 색 계산을 진행한다.
discard를 통해 예외처리 할 수 있다.

각 Fragment마다 실행되며, 동일 픽셀에 대해 여러 번 실행될 수 있다 (overdraw)


Output Merger

PS로 넘어 온 출력에

  • Depth Test ( 새 픽셀 vs 기존 깊이 비교 )
  • Stencil Test ( Stencil 버퍼 기반 조건 검사 )
  • Blending ($FinalColor = SrcColor * SrcFactor + DestColor * DestFactor$)
    을 처리하고
    Frame Buffer에 기록한다.

각 Fragment마다 실행되며, 동일 픽셀에 대해 여러 번 실행될 수 있다 (overdraw)


내용에 대한 질의나, 수정 요청은 저에게 큰 도움이 됩니다.

'그래픽스' 카테고리의 다른 글

DX11 코드 기반 그래픽스 파이프라인  (0) 2026.04.30