렌더링 파이프라인은 3차원 장면의 기하학적 서술과 가상 카메라의 위치 및 방향이 주어졌을 때, 현재 가상 카메라에 비친 3차원 장면의 모습에 근거해서 2차원 이미지를 생성하는데 필요한 일련의 단계들 전체를 가리키는 용어이다.
5.5 입력 조립기 단계
입력 조립기 (input assembler: IA) 단계는 메모리에서 기하 자료(정점들과 색인들)를 읽어서 기하학적 기본도형을 조립한다.
5.5.1 정점
정점은 기하 도형을 특징짓는 고유한 점이다. Direct3D의 정점은 공간적 위치 이외의 정보도 담을 수 있다. 이 덕분에 복잡한 렌더링 효과의 구현이 가능해진다. 조명 구현을 위해 정점에 법선 벡터를 추가하거나, 텍스처 적용을 위해 정점에 텍스처 좌표를 추가할 수 있다. Direct3D는 응용 프로그램이 자신만의 정점 형식을 정의할 수 있는(즉, 정점의 성분들을 직접 정의할 수 있는) 유연성을 제공한다.
5.5.2 기본도형 위상구조
정점들은 정점 버퍼(vertex buffer)라고 하는 특별한 Diret3D 자료구조 안에 담겨서 렌더링 파이프라인에 묶인다. 정점 버퍼 자체에는 기본도형을 형성하기 위해 정점들을 조합하는 방법에 관한 정보가 들어 있지 않다. 정점 자료를 이용해서 기하학적 기본도형을 형성하는 방법을 Diret3D에 알려주려면 기본도형 위상구조(primitive topology)라는 것을 설정해야 한다.
void ID3D12GraphicsCommandList::IASetPrimitiveTopology(
D3D_PRIMITIVE_TOPOLOGY Topology);
typedef enum D3D_PRIMITIVE_TOPOLOGY
{
D3D_PRIMITIVE_TOPOLOGY_UNDEFINED = 0,
D3D_PRIMITIVE_TOPOLOGY_POINTLIST = 1,
D3D_PRIMITIVE_TOPOLOGY_LINELIST = 2,
D3D_PRIMITIVE_TOPOLOGY_LINESTRIP = 3,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5,
D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = 10,
D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = 11,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = 12,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = 13,
D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST = 33,
.
.
.
D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST = 64,
} D3D_PRIMITIVE_TOPOLOGY;
이후의 모든 그리기 호출은 현재 설정된 기하구조 위상구조를 사용한다.
mCommandList->IASetPrimitiveTopology(
D3D_PRIMITIVE_TOPOLOGY_LINELIST);
/* ...draw objects using line list... */
mCommandList->IASetPrimitiveTopology(
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
/* ...draw objects using triangle list... */
mCommandList->IASetPrimitiveTopology(
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
/* ...draw objects using triangle strip... */
5.5.2.1 점 목록
D3D_PRIMITIVE_TOPOLOGY_POINTLIST를 지정해서 IASetPrimitiveTopology를 호출하면 정점은 개별적인 점으로 그려진다.
5.5.2.2 선 띠
D3D_PRIMITIVE_TOPOLOGY_LINESTRIP을 지정하면 정점들은 차례로 연결된 선분들을 형성한다.
5.5.2.3 선 목록
D3D_PRIMITIVE_TOPOLOGY_LINELIST를 지정하면 매 정점 두 개가 하나의 선분을 형성한다. 정점 2n개로 선분 n개가 만들어진다.
5.5.2.4 삼각형 띠
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP을 지정하면 정점들은 연결되어서 삼각형들을 형성한다. n개의 정점으로 n - 2개의 삼각형이 만들어진다. 짝수 번째 삼각형과 홀수 번째 삼각형의 정점들이 감기는 순서가 다르다는 점을 주목하기 바란다. 후면 선별에 문제가 발생하는데, 이를 위해 GPU는 내부적으로 짝수 번째 삼각형의 처음 두 정점의 순서를 맞바꾸어서 홀수 번째 삼각형과 같은 순서가 되게 만든다.
5.5.2.5 삼각형 목록
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST를 지정하면 매 정점 세 개가 하나의 삼각형을 형성한다. 3n개의 정점으로 n개의 삼각형이 만들어진다.
5.5.2.6 인접성 정보를 가진 기본도형
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ로 지정하면 각 삼각형에 그에 접한 이웃 삼각형 세 개에 관한 정보를 포함할 수 있다. 그렇게 만든 삼각형 목록을 "인접성(adjacency) 정보를 가진 삼각형 목록"이라고 부르고, 주어진 삼각형에 접한 삼각형들을 인접 삼각형(adjacent triangle)이라고 부른다. 이러한 삼각형 목록은 인접 삼각형들에 접근해야 하는 특정한 기하 셰이딩 알고리즘을 기하 셰이더에서 구현할 때 쓰인다. 인접 기본도형의 정점들은 오직 기하 셰이더의 입력으로만 쓰일 뿐, 실제로 그려지는 것은 아님을 주의하기 바란다.
5.5.2.7 제어점 패치 목록
D3D_PRIMITIVE_TOPOLOGY_N_CONTROL_POINT_PATCHLIST 위상구조는 정점 자료를 N개의 제어점(control point)들로 이루어진 패치 목록으로 해석해야 함을 뜻한다.
5.5.3 색인
사각형과 팔각형을 삼각형 목록을 이용해서 구축한다면 다음은 이에 필요한 정점 배열들이다.
Vertex quad[6] = {
v0, v1, v2, // Triangle 0
v0, v2, v3, // Triangle 1
};
Vertex octagon[24] = {
v0, v1, v2, // Triangle 0
v0, v2, v3, // Triangle 1
v0, v3, v4, // Triangle 2
v0, v4, v5, // Triangle 3
v0, v5, v6, // Triangle 4
v0, v6, v7, // Triangle 5
v0, v7, v8, // Triangle 6
v0, v8, v1 // Triangle 7
};
하나의 3차원 물체를 형성하는 삼각형들은 여러 개의 정점을 공유한다. 배열에는 이 정점들이 중복되어 들어 있음을 주목하기 바란다. 일반적으로, 모형이 세밀하고 복잡할수록 중복되는 정점들도 많다. 정점들의 중복이 바람직하지 않은 이유는 크게 두 가지이다.
- 메모리 요구량이 증가한다. 같은 정점 자료를 여러 번 저장할 필요가 있겠는가?
- 그래픽 하드웨어의 처리량이 증가한다. 같은 정점 자료를 여러 번 처리할 필요가 있겠는가?
삼각형 띠를 이용하면 중복 정점 문제가 완화된다. 단, 모형이 기하구조를 삼각형 띠 형태로 구성할 수 있어야 하는데, 항상 가능하지는 않다. 삼각형 띠보다는 삼각형 목록이 더 유연하므로(삼각형들이 연결될 필요가 없다는 점에서), 삼각형 목록에서 중복 정점들을 제거하는 방법을 고안하는 것은 가치가 있는 일이다. 해결책은 색인(index)을 사용하는 것이다. 색인을 이용하는 정점 목록과 함께 색인 목록을 하나 만든다. 색인 목록은 어떤 정점들을 어떤 순서로 사용해서 삼각형을 형성해야 하는지를 나타내는 색인들로 이루어진다.
Vertex v[4] = {v0, v1, v2, v3};
정점 목록의 정점들로 두 개의 삼각형을 형성하는 방법을 결정하는 색인 목록을 만들어야 한다.
UINT indexList[6] = {0, 1, 2, // Triangle 0
0, 2, 3}; // Triangle 1
위는 정점 0, 1, 2로 삼각형 0을 만들고, 정점 0, 2, 3으로 삼각형 1을 만들라는 뜻이다. 마찬가지로 팔격형을 위한 정점 목록은
Vertex v [9] = {v0, v1, v2, v3, v4, v5, v6, v7, v8};
로 두고, 색인 목록은
UINT indexList[24] = {
0, 1, 2, // Triangle 0
0, 2, 3, // Triangle 1
0, 3, 4, // Triangle 2
0, 4, 5, // Triangle 3
0, 5, 6, // Triangle 4
0, 6, 7, // Triangle 5
0, 7, 8, // Triangle 6
0, 8, 1 // Triangle 7
};
로 두면 된다. 그래픽 카드는 정점 목록의 고유한 정점들을 처리한 후, 색인 목록을 이용해서 정점들을 조합해 삼각형을 형성한다. 정점 목록의 '중복'이 색인 목록으로 옮겨간 셈인데, 별로 문제가 되지 않는다. 이유는 다음 두 가지이다.
- 색인은 그냥 정수이므로 완전한 정점 구조체보다 적은 양의 메모리를 차지한다. 정점에 새로운 성분을 더 추가하면 정점 구조체가 더욱 커진다.
- 정점들이 적절한 순서로 캐시에 저장된다면, 그래픽 하드웨어는 중복된 정점들을 (너무 자주) 처리할 필요가 없다.