유니티의 렌더 파이프라인

LWRP, URP

 

 

 

렌더링 파이프라인은 3D 데이터들이 2D 이미지로 구성되어 그려지는 일련의 과정을 뜻한다. 

 

◎ 렌더링 파이프라인

렌더링 파이프라인에서 데이터를 처리하는 과정을 간략하게 나눠 보자면 다음과 같다.

 

실제 파이프라인은 더 많은 과정을 거치고 플랫폼마다 다를 수 있지만 공통적이고 핵심적인 과정만 뽑자면 이 세 단계를 거치게 된다.

 

플리케이션 스테이지

애플리케이션 스테이지는 애플리케이션 상에서 처리되는 단계를 의미한다.

그래픽스 렌더링 파이프라인은 보통 GPU 파이프라인을 의미하므로 CPU에서 연산되는 애플리케이션 스테이지는 포함되지 않지만 본격적인 렌더링 파이프라인 진입 전 CPU에서 필요한 연산들을 처리해야 하므로 큰 의미로는 렌더링 파이프라인의 일부분이 된다. 

ex) 플레이어의 매 프레임마다의 움직임, 애니메이션 정보와 뼈대 위치 연산 및 메시의 버텍스에 반영 등

 

현재 프레임에서 렌더링 가능한 오브젝트들이 컬링 연산에 의해 구별된다. 

이 컬링 단계에서 효율적으로 오브젝트들이 선별되어 렌더링 되는 오브젝트 수를 줄이면 그만큼 GPU에서 처리하는 연산량이 줄게 된다. 

또한 배칭처리를 위한 연산도 GPU 파이프라인에 진입하기 전에 이루어진다. 

 

지오메트리 스테이지

이 스테이지에서는 말 그대로 지오메트리 관련 정보, 즉 지오메트리를 구성하는 요소인 버텍스와 폴리곤 처리를 담당하며 아래와 같은 과정들을 거친다.

1. 월드-뷰-프로젝션 트랜스폼
2. 클리핑
3. 버텍스 쉐이더

 

버텍스 트랜스폼(Vertex Transform)?

더보기

렌더링을 수행해야 되는 시점에 GPU가 메모리로부터 버텍스 정보를 가져와 적절한 위치에 그려주기 위해서 수행하는 트랜스폼이다. 

 

 

래스터라이저 스테이지

이 스테이지에서는 오브젝트를 그리는 픽셀들을 추리고 그 픽셀의 색을 결정한다.

버텍스 쉐이더를 거쳐서 지오메트리들이 구축되면, 화면(혹은 버퍼)의 어느 픽셀에 그려져야 하는지 결정된다.

메시의 폴리곤에 속한 영역을 픽셀로 매칭시키는 과정을 래스터라이제이션이라고 부른다. 

 

레스터라이제이션이 끝나면 최종적으로 화면에 그려져야 할 픽셀의 최종 색이 결정된다.

즉, 해당 스테이지에서는 렌더링하는 메시가 화면에 매칭되는 픽셀을 결정하고 최종 색을 입히는 과정이다.

 

뎁스 버퍼, Z-버퍼를 이용해 깊이 판정을 하고 블렌딩을 통해 최종 출력 색상을 결정한다.

 

블렌딩?

더보기

투명도를 가지는 오브젝트는 픽셀 렌더링 시 알파 블렌딩 과정을 거친다.

알파 블렌딩은 쉐이더에서 결정되는 알파값을 이용한다. 픽셀 출력의 알파값을 이용해서 해당 픽셀 위치의 컬러 버퍼의 기존 값과 적절하게 혼합해 최종 출력 색상을 결정한다. 

 

 

 

 

◎ 유니티가 제공하는 파이프라인 

유니티는 2018년부터 유니티의 렌더링 처리 방식을 C# 스크립트로 제어할 수 있는 기능인 SRP(Scriptable Render Pipeline) 기능을 제공했다.

이를 통해 전반적인 렌더링 루프를 직접 구성할 수 있으며 직접 렌더링 루프를 커스터마이징해 원하는 방식으로 렌더링을 구성할 수 있게 되었다. 

또한 SRP의 등장과 함께 유니티에 기본적으로 구현되어 있는 기본 렌더링 파이프라인빌트인(내장) 파이프라인이라고 부르게 되었다. 

 

 

1. HDRP (High Definition Render Pipeline)

하이엔드나 PC 콘솔 등을 고려해서 고품질의 비주얼 구현에 적합한 파이프라인이다.

포워드 렌더링, 디퍼드 렌더링을 모두 지원하며 컴퓨터 쉐이더 기술과 GPU 하드웨어를 사용한다. 

하지만 기본적으로 요구되는 하드웨어 스펙이 높아서 모바일 게임용으로는 적합하지 않다.

 

2. URP (Universal Render Pipeline)

Unity 2019.3 버전부터 LWRP(Lightweight Render Pipeline)이 유니버설 렌더 파이프라인으로 변경되었다. 

 

LWRP는 모든 모바일 디바이스에서 고품질 그래픽스를 구현하는 빠르고 확장 가능한 파이프라인이다. 

URP는 기본 빌트인 렌더 파이프라인보다 유연하고 확장성이 좋으며 다양한 플랫폼에 최적화된 그래픽을 제공한다.

싱글 패스 포워드 렌더링과 셰이더 그래프, VFX 그래프를 지원한다. 

https://blog.unity.com/kr/technology/how-the-lightweight-render-pipeline-is-evolving

 

 

 

참고 자료;

유니티 그래픽스 최적화 스타트업 (저; 오지현(오즈라엘), 출판사; 비엘북스, 감수; 정종필) 

 

 

렌더링 파이프라인(Rendering Pipeline)

 

GPU를 사용해 리소스를 2D 이미지로 렌더링 하는 과정이다.

파이프라인은 여러 개의 파이프라인 단계로 구성되어 있으며 프로그램 가능 단계와 고정 프로그램 단계로 구분된다. 

 

 

 

 

렌더링 파이프라인을 구성하는 단계들과 관련 GPU 메모리 자원들

 

 

고정 프로그램 단계?

Direct3D에서 모든 처리가 진행되며 응용 프로그램에서 변경할 수 없는 단계

- 입력 조립(IA) 단계, 테셀레이터 (TS) 단계, 스트림 출력(SO) 단계, 래스터라이저(RS) 단계, 출력 병합(OM) 단계

 

프로그램 가능 단계?

응용 프로그램에서 쉐이더 프로그램을 통해 제공해야 하는 단계

- 정점 쉐이더(VS) 단계, 헐 쉐이더(HS) 단계, 도메인 쉐이더(DS) 단계, 기하 쉐이더(GS) 단계, 픽셀 쉐이더(PS) 단계

 

 

위의 파이프라인에서 오른쪽은 자원 메모리 풀을 뜻한다. 자원 메모리 풀에서 파이프라인의 단계로 가는 화살표는  그 단계가 자원을 입력으로 사용할 수 있음을 뜻하고 파이프라인의 단계에서 자원으로 가는 화살표는 그 단계가 GPU 자원에 자료를 기록할 수 있음을 뜻한다. 

 

 

 

◎ 입력 조립기 (Input Assembler) 단계

고정 함수 단계이다. 응용 프로그램에서 제공받은 정점 버퍼의 정점 데이터(프리미티브 데이터 : 점, 선, 삼각형)를 다른 파이프라인 단계에서 사용할 프리미티브(선 리스트, 삼각형 리스트, 삼각형 스트립, 인접성을 가지는 프리미티브 등)로 조립한다. 

즉, 메모리에서 기하 자료(정점 데이터와 Index(색인))를 읽어 기하학적 기본도형(삼각형, 선분 등)을 조립한다. 

 

그럼 정점이란 무엇일까?

더보기

Direct3D에서의 정점은 공간적 위치, 즉 위치 값 이외의 정보를 담고 있으며 이를 통해 좀 더 복잡한 렌더링 효과를 구현할 수 있다. 예를 들면 조명 구현을 위해 정점에 법선 벡터를 추가하거나 텍스처를 적용하기 위해 텍스처 좌표를 추가하는 식으로 사용할 렌더링 효과에 따라 특정 정보를 추가할 수 있는 유연성을 갖고 있다. 

 

 

 

◎ 정점 쉐이더 (Vertext Shader) 단계

이 단계에서는 입력 조립 단계에서 출력되는 Primitive의 각 정점에 대한 연산을 수행한다. 

이 정점 쉐이더는 항상 모든 정점들에 대해 한 번씩 실행된다. 또한 하나의 정점에 대해 한 번만 호출되며 하나의 출력 정점을 생성될 뿐 아니라 파이프라인 단계에서 항상 수행이 되어야 하는 단계이다. 따라서 정점에 대한 변환이 필요하지 않아도 정점 쉐이더를 생성해 연결해야 한다. 

 

이 정점 셰이더 함수의 구체적인 내용은 프로그래머가 구현해서 GPU에 전달하게 된다. 그 함수는 각 정점에 대해 GPU에서 실행되기 때문에 속도가 빠르다. 

변환(Transformation), 스키닝(Skinning), 조명(Vertex Lighting) 등 수많은 특수 효과를 정점 쉐이더에서 수행할 수 있다. 정점 쉐이더에서 입력 정점 자료는 텍스쳐라든가 변환 행렬, 장면 광원 정보 등 GPU 메모리에 담긴 다른 자료에도 접근할 수 있다. 

 

더보기

이 단계에서 일어나는 작업 중 변환이 어느 물체의 로컬 좌표를 월드 좌표로, 월드 좌표를 뷰 스페이스 좌표로 바꿔주고 투영 변환등이 일어나는 변환 작업이다.

 

 

 

 

◎ 테셀레이션 단계

테셀레이션이란 한 메시의 삼각형들을 더 잘게 쪼개서 새로운 삼각형들을 만드는 과정을 말한다.

 

테셀레이션의 장점은

  1.  LOD 구현이 가능하다.
    더보기
    LOD란 Level-of-detail를 말한다.
    카메라에 가까운 삼각형들은 테셀레이션을 적용해 더욱 세밀한 구현을 적용하고 멀리 있는 삼각형들은 테셀레이션을 적용하지 않는 방식의 세부 수준 메커니즘을 구현해 눈에 띄는 부분에 대해서만 삼각형을 더 투여할 수 있게 된다. 
  2.  Low-poly 메시, 적은 수의 삼각형들로 이루어진 메시를 담아두고 즉석에서 삼각형들을 추가해 메모리를 적용할 수 있다.
  3.  애니메이션, 물리 처리 같은 연산들을 단순한 Low-Poly 메시에 대해 수행하고, 테셀레이션 된 High-Poly 메시는 렌더링에만 사용해 계산량을 줄일 수 있다. 

 

 

 

◎ 기하 셰이더 (Geometry Shader) 단계

이 단계는 정점 셰이더의 처리를 거친 정점 데이터를 입력받는다. 그리고 입력받은 정점에 정보를 추가하거나 삭제해 입력 기본도형을기본 도형을 다른 여러 기본 도형들로 확장할 수도, 특정 조건에 따라서는 입력된 기본 도형을 출력하지 않고 버릴 수도 있다. 

기하 셰이더의 흔한 용도는 하나의 점이나 선분을 하나의 사각형으로 확장하는 것이다. 

 

 

 

◎ 래스터라이저(Rasterizer) 단계

이 단계는 투영된 3차원 삼각형으로부터 픽셀 색상들을 계산해 내는 것이다. 

Rasterization을 하는 동안 각 프리미티브를 구성하는 정점은 픽셀로 변환되고 프리미티브의 내부에 해당하는 점들은 보간을 통해 픽셀로 변환된다.

 

과정

1. 원근 투영 나누기(z 나누기)

2. 카메라 절두체를 벗어나는 점(Pixel)들을 클리핑(Clipping)

3. Primitive를 2차원 Viewport로 매핑

4. Primitive의 모든 픽셀들에 대해 픽셀 쉐이더를 호출

 

 

 

 

◎ 픽셀 셰이더 (Pixel Shader) 단계

각 픽셀의 데이터(기본적으로 색상)를 생성한다. 프로그래머가 작성해서 GPU에서 실행하는 프로그램으로 각각의 필셀 단편(pixel fragment)마다 실행된다. 

상수 변수, 텍스처 데이터, 또는 픽셀 출력 데이터 등을 결합해 출력 색상을 결정한다.

이 단계에서 픽셀 조명 계산 또는 픽셀에 대한 후처리를 할 수 있다. 

 

하나의 프리미티브를 구성하는 각 픽셀에 대해 픽셀 쉐이더를 한 번씩 호출한다. 

다중 샘플링을 사용한다면 깊이/스텐실 테스트는 각 서브픽셀에 대해 한 번씩만 수행되며 다중 샘플링을 사용해도 이 픽셀 쉐이더는 하나의 픽셀에 대해 한 번만 호출된다.

 

 

 

 

◎ 출력 병합기 (Output Merge) 단계

픽셀 셰이더가 생성한 픽셀 단편들은 이 단계로 입력된다. 최종적으로 픽셀의 색상을 생성해 렌더 타깃으로 출력하는 단계이다. 이 단계에서 일부 픽셀 단편들이 깊이 판정이나 스텐실 판정에 의해 버려지게 되며 버려지지 않은 픽셀 단편은 후면 버퍼에 기록된다.

흔히 말하는 블렌딩도 이 단계에서 일어난다.

더보기

블렌딩은 새 픽셀이 후면 버퍼의 기존 픽셀을 완전히 덮어 쓰는 것이 아니라 두 픽셀을 일정한 공식에 따라 혼합한 결과를 기록하는 것을 말한다. 

렌더 타겟의 픽셀 색상과 출력(픽셀 쉐이더) 색상을 결합한다. 

 

- 깊이-스텐실 검사(Depth-Stencil Testing)

픽셀이 그려져야 하는지를 결정하기 위해 깊이 값과 스텐실 값 데이터를 사용한다.

하나의 깊이/스텐실 버퍼만 활성화 되며 깊이-스텐실 버퍼에 스텐실 요소가 없으면 스텐실 검사는 항상 성공한다.

또한 깊이-스텐실 버퍼가 파이프라인에 연결되지 않으면 스텐실 검사는 항상 성공한다. 

 

깊이 검사?

더보기

z = min(Viewport.MaxDepth, max(Viewport.MinDepth, z))

출력 픽셀의 깊이 값을 깊이 버퍼의 같은 위치의 깊이 값과 비교한다. 

비교의 결과에 따라 출력 픽셀을 렌더 타깃에 출력하거나 출력하지 않는다.

 

 

 

 

 

 

 

 

참고 출처

Direct11을 이용한 3D게임프로그래밍 (저; 프랭크 D. 루나, 역; 류광, 출판사; 한빛미디어)

+ Recent posts