Direct3D 12 graphics Pipeline
- 아래와 같은 구조의 pipeline을 통해 GPU는 rendering을 한다.
- 전체 pipeline을 frame 마다 수행
- 한 스테이지의 output은 다음 stage의 input이 된다.
- Shader : programming 가능
- Input assembler, Tessellator, Rasterizer, Output merger : hard-wired(역할, 목적이 고정되어있는) stage이다. 고정된 함수만 사용하여 일을 수행한다.

먼저 Shader에 대한 간단한 정보들..
Shader
- 프로그래밍 가능한 영역 (programmable)
- floating point 연산이 배우 빠르다
- 특정 program guideline(ex. input output structure)에 맞게 디자인 되어야 함.
- 랜더링 파이프라인에는 5가지 종류가 있음 (Vertex, Hull, Domain, Geometry, Pixel)
- vertex shader : 생략 불가능
- pixel shader : 생략 가능
- DirectX : HLSL / OpenGL : GLSL
Input-Assembler Stage (IA)
◇ vertex 정보들을 primitive(도형 - 삼각형, 선 등) 단위로 묶는 역할
- user-specified buffer(vertex, index buffer)에서 vertex 정보를 읽는다.
- user들은 IASetPrimitiveTopolgy(data를 어떻게 자를 건지)를 활용하여 primitive type를 정할 수 있다.
Vertex Shader
◇ vertex의 최종 position 계산 + camera space에 표시될 vectex 선별
- Input : vertex specifications
- vertex specifications : input-assembler에서 vertex,index buffer를 통해 제공된다.
- 각 vertex 마다 한번씩 동작한다.
- 참고로 GPU는 for문이 안좋다 - dependancy 때문에 성능이 저하될 수 있기 때문

Vertex 좌표 변환 과정

Object space
- 오브젝트 내에서의 위치
- 오브젝트에 따라 axes가 바뀐다
- = model space
World space
- 3D World space에서의 위치
Camera space
- Camera를 중점으로 한 상대좌표
- world space coordinate가 target camera를 기준으로 다시 계산된다.
- = eye space
Clip space
- camera space에서 projection transform을 한 것
World Transform
◇ scaling, roation, translation 과정을 통해 object space → world space로 옮겨준다.
- 기존의 object space에서는 각 model들끼리 독립적인 공간이다.
- 반면 world space에서는 모든 model들을 assemble = 하나의 coordinate system으로 합치는 것
- World Matrix =
- L = combined linear transform
- t = combined translation

World Transform - normal vector
◇ normal vector가 찌그러지는 것을 방지하기 위해 inverse transpose를 사용해야 한다.
- non-uniform scaling : 객체의 각 축(x, y, z)을 서로 다른 비율로 확대/축소하는 스케일 변환
- non-uniform scaling이 있을 때, normal에도 그대로 L을 곱해주게 되면 아래 사진처럼 normal이 직교하지 않고 찌그러진다

- 해결 방법 : normal에는

View Transform
◇ 월드 좌표(World Space)를 카메라 기준 좌표(View Space)로 변환하는 과정
- '카메라를 움직이는 것이 아니라, 세상을 카메라 기준 좌표계로 바꾸는 것' 이라고 생각하면 편하다.
- 아까 world matrix가 있었던 것 처럼 여기도 View Matrix를 계산해서 사용한다.
- camera space : (u, v, n, EYE) - 이때 EYE는 카메라의 위치이다.
- world space : (e1, e2, e3, O)
Step 1) 카메라 위치(EYE)를 world space의 원점으로 translation
- 즉, world space 전체를 −EYE 만큼 이동한다.

Step 2) 좌표축 정렬 (Rotation / Basis Change)
- 이제 카메라의 좌표축 (u, v, n)을 월드 좌표축 (e1, e2, e3)와 맞춰야 한다.

View Transform - View Matrix
그럼 위와 같은 과정을 거쳐서 최종 View Matrix는 아래와 같다.

View Frustum (절두체)
◇ 우리가 볼 수 있는 영역을 의미하며 view volume이라고도 부른다.
- field of view(fov)가 제한되어있기 때문에 카메라는 모든 물체를 볼 수 없다.
- 4가지 변수들 : fovy(시야각), aspect(넓이-높이의 비율), n(가장 가까운 지점), f(가장 먼 지점)
- 변수들을 활용해서 아래 사진 처럼 사다리꼴 또는 공간을 정의할 수 있다.
- culling이나 clipping을 통해서 보여지지 않는 부분은 버려지게 된다.

View frustum culling
◇ 시야 밖의 object를 없애버리자
- out of frustum인 물체들은 GPU pipeline에 들어가기전에 버려진다(discard).
- discard의 의미는 아예 memory에 올리지 않거나 음수로 만들어 다음 stage에서 제외시키는 방법이 있다.
Clipping (by the rasterization stage)
◇ 시야에 걸리는 일부분만 가져오자
- 레스터라이저가 하는 일이기 때문에 자세한 것은 이후에 설명할 예정,,

Projection Transform
◇ view frustum → 정규화된 cube 로 변환
- view frustum을 원점을 중심으로 하는 axis-aligned cube에 다시 위치시킨다.
- 위에 clipping을 언급했는데, 피라미드 형태에서 하는 것이 아니라 이 단계에서 큐브 형태로 만든 후에 clipping을 하게된다.
- 피라미드에서 clipping을 하게 되면 훨씬 복잡해지 때문..
- homogeneous coordinate의 w에 깊이 정보를 저장하여 이후 수행되는 perspective divide를 통해 원근 투영 효과가 생성된다.

- DirectX (LHS) vs OpenGL (RHS)

Projection Transform Matrix
◇ DirectX 기준 최종 Matrix
- 아까 위에서 설명했던 view frustum의 변수들로 구성되어있다.
- 마지막 행이 왜 (0 0 1 0) 일까? → 이건 레스터라이저에서 perspective divide을 할 때 필요하다. 다음 정리에서 설명될 예정

◇ OpenGL 기준 최종 Matrix
- 요건 참고용으로 가져왔는데, 마지막 행 -1이 들어가는 것을 볼 수 있다.

- rasterizer는 shader와 달리 사용자가 수정할 수 없다.
- rasterizer는 clip space를 LHS로 취급하기 때문에 shader에서 미리 RHS → LHS로 변환해줘야 한다.
- 이를 위해 z축에 대해 -1을 곱해주게 되는데, 이 과정을 하지 않으면 아래 사진 처럼 뒤집어진 그림이 나오게 된다.

Reference KHU 강형엽 교수님 강의를 수강하며 정리한 내용입니다.
'그래픽스' 카테고리의 다른 글
| [DirectX12] 5. Output Merger (1) | 2026.04.10 |
|---|---|
| [DirectX12] 4. Pixel Shader - Lighting (0) | 2026.03.13 |
| [DirectX12] 3. Pixel Shader - Texturing (0) | 2026.03.13 |
| [DirectX12] 2. Rasterizer (1) | 2026.03.13 |