본문 바로가기

DirectX/DirectX11 기초 개념

Direct3D 11 렌더링 파이프라인

DirectX 11로 시작하는 3D 게임 프로그래밍 // 이용희 지음 // 프레릭

 

 

1. Direct3D 11 렌더링 파이프라인

 

Direct3D 렌더링 파이프라인GPU를 사용하여 메모리의 리소스(정점/인덱스 버퍼, 텍스처)2차원 이미지(픽셀)렌더링하는 일련의 과정을 의미한다.

 

이 파이프라인은 여러 개의 작은 논리적인 단위(파이프라인 단계, Pipeline Stage)로 구성되며 프로그램 가능 단계와 고정 프로그램 단계로 구분된다.

 

고정 프로그램 단계는 Direct3D 라이브러리에서 모든 처리가 진행되며 응용 프로그램에서 프로그래밍 할 수 없는 단계이다.

  • Input Assembler Stage
  • Tessellator Stage
  • Stream Output Stage
  • Rasterizer Stage
  • Output Merger Stage

 

프로그램 가능 단계는 응용 프로그램에서 셰이더 프로그램을 통하여 제공해야하는 단계이다.

  • Vertex Shader Stage
  • Hull Shader Stage
  • Domain Shader Stage
  • Geometry Shader Stage
  • Pixel Shader Stage

 

docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-graphics-pipeline?redirectedfrom=MSDN

 

 

 

2. 입력 조립 단계(Input Assembler Stage)

 

입력 조립 단계(IA 단계)는 Direct3D 11 렌더링 파이프라인의 첫 번째 단계이며 고정함수로 구성된다.

즉, 사용자가 프로그래밍할 수 없으며 Direct3D API가 제공하는 기능을 그대로 사용해야한다.



목적

1. 응용프로그램에서 제공한 정점 버퍼로부터 정점 데이터(프리미티브 데이터(점, 선, 삼각형))를 다른 파이프라인 단계에서 사용할 프리미티브로 조립하는 것

 

2. 시스템 생성 값을 추가하는 것. 이 값은 시맨틱(Semantic)이라고 하는 문자열이며 다음 단계의 셰이더에서 유용하게 쓰인다.

시스템 생성 값의 예는 프리미티브 ID, 인스턴스 ID, 정점 ID 등이다.



결론적으로 입력 조립 단계는 입력된 정점 데이터를 읽어서 프리미티브를 조립하고 시스템 생성 값을 추가하여 다음 단계인 정점 셰이더 단계로 출력하는 것이라 하겠다.



과정

1. 입력버퍼(정점 버퍼 또는 인덱스 버퍼) 객체를 생성

2. 입력 레이아웃 객체 생성. 입력 레이아웃 객체는 정점 버퍼의 한 원소의 구조를 나타낸다.

3. 입력 버퍼와 입력 레이아웃 객체를 입력 조립 단계에 연결한다.

4. 프리미티브 유형을 지정한다. 입력 조립단계는 입력 데이터를 이 프리미티브로 조립한다.

5. 그리기 함수를 호출한다. 입력 조립 단계는 조립한 데이터시스템 생성값을 Direct3D 파이프라인으로 전달한다.



3. 셰이더 단계들

  • 정점 셰이더 단계(Vertex Shader Stage)
  • 헐 셰이더 단계(Hull Shader Stage)
  • 도메인 셰이더 단계(Domain Shader Stage)
  • 기하 셰이더 단계(Geometry Shader Stage)
  • 픽셀 셰이더 단계(Pixel Shader Stage)

 

공통 셰이더 코어의 데이터 흐름

{

docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-common-core



입력 데이터(Input Data)

각 셰이더는 Direct3D 렌더링 파이프라인에서 해당 셰이더의 바로 앞 단계의 출력을 입력 데이터로 사용한다.

 

출력 데이터(Output Data)

각 셰이더는 Direct3D 렌더링 파이프라인에서 바로 다음 단계로 전달할 출력 데이터를 생성한다.

 

셰이더 코드(Shader Code)

셰이더는 메모리의 셰이더 리소스를 읽고 벡터 실수 연산과 정수 산술 연산 또는 흐흠 제어 연산을 수행할 수 있다.

 

샘플러(Sampler)

샘플러는 텍스처를 샘플링하고 필터링하는 방법을 정의한다.

하나의 셰이더에 동시에 16개의 샘플러가 연결될 수 있다.

 

텍스처(Texture)

텍스처는 샘플러를 사용하여 필터링될 수 있다.

또는 Load()함수를 사용하여 텍셀을 읽을 수 있다.

Load() 함수를 사용하여 텍셀을 읽을 때는 필터링 또는 샘플링이 일어나지 않는다.

 

버퍼(Buffer)

버퍼는 셰이더의 데이터를 저장하는 메모리 영역이다.

버퍼는 필터링되지 않지만, Load() 함수를 사용하여 버퍼의 원소를 읽을 수 있다.

하나의 셰이더에 동시에 128개의 텍스처와 버퍼 리소스가 연결될 수 있다.

 

상수 버퍼(Constant Buffer)

상수 버퍼는 셰이더 호출마다 변하지 않는 값을 저장하기 위한 메모리 영역이다.

상수 버퍼는 셰이더 상수 변수를 위하여 최적화된다.

하나의 셰이더에 동시에 16개의 상수 버퍼가 연결될 수 있다.

}



 

 

  • 정점 셰이더 단계(Vertex Shader Stage)

정점에 대한 변환 또는 수정이 필요하지 않더라도 정점 셰이더는 생성되고 파이프라인에 연결되어야 한다.

 

모든 정점 셰이더는 최소 하나 이상의 입력과 하나 이상의 출력이 있어야 한다.

 

입력 조립기에서 생성한 두 개의 시스템 생성 시맨틱을 사용할 수 있다.

 

정점 셰이더는 항상 모든 정점들에 대하여 실행된다.



 

 

  • 기하 셰이더 단계(Geometry Shader Stage)

정점들을 입력받아 새로운 정점들을 생성한다.

 

기하 셰이더에서 입력은 완전한 하나의 프리미티브를 구성하는 정점들이다.

 

기하 셰이더 단계는 입력 조립기가 자동으로 생성하는 SV_PrimitiveID 시스템 생성 시맨틱 값을 사용할 수 있다.

이것은 프리미티마다 데이터를 가져와서 계산하는 방법을 제공한다.

 

기하셰이더 단계는 하나의 프리미티브를 구성하는 여러개의 정점을 출력할 수 있다.

 

기하셰이더 단계에서 출력은 래스터라이저 단계 또는 스트림 출력 단계를 거쳐 정점 버퍼로 입력될 수 있다.

 

기하 셰이더가 활성화되면 기하 셰이더는 파이프라인의 이전 단계에서 이미 생성된 각 프리미티브에 대하여 한 번씩 호출된다.

 

기하 셰이더는 출력 스트림 객체에 정점들을 추가함으로써 한 번에 하나의 정점을 출력한다.



 

 

  • 픽셀 셰이더 단계(Pixel Shader Stage)

픽셀 셰이더 단계는 상수 변수, 텍스처 데이터, 또는 픽셀 출력을 위한 데이터 등을 결합하여 각 픽셀의 데이터(기본적으로 색상)을 생성한다.




4. 스트림 출력 단계(Stream Output Stage)

 

스트림 출력(Stream-Output Stage, SO) 단계의 목적은 기하 셰이더 또는 정점 셰이더로부터 정점 데이터를 연속적으로 메모리의 버퍼로 출력(스트림)하는 것이다.

 

이 단계에서 버퍼로 출력된 데이터는 렌더링 파이프라인에서 다시 읽어들일 수 있다.

 

또한, CPU에서 읽어들일 수 있도록 다른 메모리 리소스로 복사될 수 있다.

 

정점들은 항상 완전한 프리미티브를 구성하도록 출력된다.

 

과정

1. 기하 셰이더를 컴파일한다.

2. 스트림 출력을 가진 기하 셰이더 객체를 생성한다.

3. 출력 대상을 설정한다.




5. 래스터라이저 단계(Rasterizer Stage)

 

래스터라이저 단계의 목적은 벡터 정보(프리미티브)를 래스터 이미지(픽셀)로 변환하는 것이다.

래스터라이제이션 동안 각 프리미티브를 구성하는 정점은 픽셀로 변환되고 프리미티브의 내부에 해당하는 점들은 보간(Interpolation)을 통하여 픽셀로 변환된다.

 

픽셀 셰이더를 호출하는 것은 선택할 수 있지만 래스터라이저 단계는 클리핑, 정점을 동차 좌표계로 변환하기 위하여 z값으로 나누고, 정점을 뷰포트로 매핑하는 것은 항상 포함해야 한다.

 

과정

{

1) 뷰포트(Viewport) 설정

 

뷰포트는 투영 좌표계의 정점 위치를 렌더 타깃 위치로 맵핑하기 위한 사각형을 나타낸다.

 

뷰포트로 매핑하는 과정에서 3차원 좌표가 2차원 좌표로 바뀐다.

 

뷰포트 좌표 변환 과정에서 y축의 방향의 부호가 반대가 된다.



2) 시저(Scissor) 사각형 설정

 

시저(Scissor) 사각형은 출력 병합 단계에서 입력되는 픽셀의 수를 줄일 수 있도록 해준다.

시저 사각형 외부의 픽셀은 버려진다.

 

가장 일반적인 설정은 뷰포트의 크기로 시저 사각형을 초기화하는 것이다.



3) 래스터라이저 상태 설정

 

래스터라이저 상태는 래스터라이저 상태 객체를 통하여 설정할 수 있다.

}



  • 깊이 바이어스

 

3D 공간에서 같은 평면의 다각형들은 각 다각형에 z 바이어스(또는 깊이 바이어스)를 더하여 같은 평면에 있지 않은 것처럼 보이게 할 수 있다.

 

깊이 바이어스 연산은 클리핑을 한 후 정점들에 적용된다. 그러므로 깊이 바이어스는 기하적 클리핑에 영향을 주지 않는다.



6. 출력 병합 단계(Output Merger Stage)

 

출력 병합(Output-Merger Stage, OM) 단계는 파이프라인 상태, 픽셀 셰이더가 생성한 픽셀 데이터, 렌더 타깃의 내용, 그리고 깊이/스텐실 버퍼의 내용을 조합하여 최종 픽셀의 색상을 생성한다.

 

이 단계는 깊이/스텐실 검사를 통하여 어떤 픽셀이 보이게 되는가를 결정하고 최종 픽셀 색상를 블렌딩하는 마지막 단계이다.



  • 깊이/스텐실 검사

 

깊이/스텐실 버퍼깊이 데이터스텐실 데이터를 함께 포함할 수 있다.

 

깊이 데이터는 어떤 픽셀이 카메라에 더 가까운가를 결정하기 위하여 사용된다.

 

스텐실 데이터는 어떤 픽셀이 갱신될 수 있는가를 매스크하기 위하여 사용된다.

 

결과적으로 깊이 값과 스텐실 값은 픽셀이 그려져야 하는지 아닌지를 결정하기 위하여 출력 병합 단계에서 사용된다.



어떤 픽셀이 그려져야 하는가를 결정하기 위하여 깊이 버퍼를 사용하는 과정은 깊이 버퍼링(Depth Buffering) 또는 z-버퍼링(z-Buffering)이라고 한다.



  • 블렌딩

 

블렌딩은 여러 개의 픽셀 값(색상)을 결합하여 하나의 최종 픽셀 색상을 생성하는 과정이다.

 

블렌딩이 활성화되지 않으면 픽셀 셰이더의 출력 색상이 렌더 타깃에 쓰인다.

 

블렌딩이 활성화되면 픽셀 셰이더의 출력 색상과 렌더 타깃의 색상을 섞어서(블렌딩) 렌더 타깃에 쓰게된다.

 

블렌딩 연산은 픽셀 셰이더의 출력 값이 렌더 타깃에 쓰이기 전에 수행된다.




  • Alpha-to-coverage

 

Alpha-to-coverage는 여러 개의 다각형이 겹치는 무성한 잎과 같은 상황에 유용한 다중 샘플링 기법이다.

 

'DirectX > DirectX11 기초 개념' 카테고리의 다른 글

Direct3D 리소스  (0) 2021.04.30
Direct3D 11 디바이스  (0) 2021.04.22
3D 그래픽과 Direct3D  (0) 2021.04.22
3D 그래픽의 이해  (0) 2021.04.22