본문 바로가기
Unity3D/Shader

유니티 셰이더&렌더링 파이프라인 공부 내용 정리

by 니키티스 2020. 9. 8.

참고 영상 : youtu.be/0XJWdNFnq50

해당 포스팅은 retr0님의 유니티 셰이더&렌더링 에센스 시리즈를 보고 공부한 내용을 정리하는 글입니다. CG에 관한 지식이 충분하지 않은 상태로 쓴 글이니 오류가 있으면 댓글로 지적해 주세요.

 

 

 

셰이더

셰이더(Shader)란?

- 화면에 색을 칠하는(Shading) 프로그램이다.

- 렌더링 파이프라인의 일부를 유연하게 변경할 수 있게 해 준다.

렌더링 파이프라인?

- 정점으로 정의된 물체를 그려내는 과정을 렌더링이라 한다.

- 화면 상에 그림을 그리는 과정을 여러 단계로 나누는 것이다. 작업을 수행하는 걸 파이프라고 하면 전체 과정은 여러 개의 파이프를 이은 것처럼 될 것이고, 이를 렌더링 파이프라인이라 부른다.

셰이더의 종류

- 버텍스 셰이더(Vertex shader) : 정점의 위치와 크기 등을 다루는 렌더링 파이프라인에 이용된다. 밑그림을 그리는 것과 비슷하다.

- 프래그먼트 셰이더(Fragment shader) : 버텍스 셰이더를 거친 정점들에게 색을 부여하고 계산하는 셰이더이다.

- 컴퓨트 셰이더(Compute shader) : 그래픽 카드상에서 동작하는 셰이더이다. 컴퓨트 셰이더로도 렌더링을 할 수는 있지만, 주로 렌더링과 직접적으로 관련이 없는 작업에 사용한다. 즉, 그래픽적인 것을 포함해 다양한 문제를 해결하기 위해 GPU의 성능을 이용하는 셰이더이다. 컴퓨트 셰이더는 렌더링 파이프라인에 속하지 않는다. 그리기 명령을 실행한다고 해도 컴퓨트 셰이더는 실행되지 않는다.

셰이더의 특징

- 셰이더는 여러 개의 정점을 한 번에 계산하지 않는다.

셰이더는 하나의 정점이 입력으로 들어오면 그 하나의 정점에 대해서만 계산과 처리를 한다. 각 정점의 수만큼 셰이더가 개별적으로 계산을 실행한다. 정점마다 계산 함수를 거쳐서 위치, 크기, 색상 등을 계산하고 처리하는 셈이다.

 

 

 

렌더링 파이프라인의 과정

위키의 정의에 따르면, 렌더링 파이프라인은 '3차원 이미지를 2차원 래스터 이미지로 표현하기 위한 단계적인 방법'이다. 래스터 이미지란 비트맵(. bmp)과 같이 화소로 표현되는 이미지이다. 간단하게 말하면 렌더링 파이프라인은 오브젝트를 화면에 표현하기 위한 일련의 작업들인 것이다. 렌더링 파이프라인은 그래픽스 파이프라인이라고도 부른다.

 

그래픽 프로그램이 렌더링 파이프라인을 시작하기 전에 여러 가지 작업을 하게 되는데, 순서대로 나열하면 이러하다.

그래픽스 API 초기화 -> 드로우 콜 생성 -> 렌더링 파이프라인 -> 최종 화면 출력

1. 그래픽스 API 초기화

- CPU가 명령을 등록하고 GPU에서 명령을 실행하는 방식을 취한다.

 

(1) GPU 디바이스 생성

- 현재 기기의 GPU를 표현하는 오브젝트

- 한 번만 생성하고 하나만 존재함

(2) 명령 대기열(Command queue) 생성

- GPU 디바이스에 전달할 명령을 저장하는 큐(Queue)이다.

- 한 번만 생성하고 하나만 존재한다.

- 이벤트 큐 방식을 떠올리면 좋을 것으로 보인다. 10개의 오브젝트가 돌아가면서 자신을 그려달라고 개별적으로 요청을 하면 즉시 그려주는 것이 아니다. CPU가 명령 리스트를 GPU의 명령 대기열에 등록하면, 나중에 GPU가 처리할 준비가 되었을 때 명령들이 실행되는 것이다.

(3) 렌더링 파이프라인 상태 생성

- 렌더링 파이프라인의 상태를 표현한다.

- 렌더링 파이프라인에서 사용할 여러 가지 속성을 가진다.

- 여러 개 생성 가능함.

- 렌더링 파이프라인 서술자 오브젝트가 존재한다.

 

렌더링 파이프라인 서술자

렌더링 파이프라인이 어떻게 동작할지를 나타내는 오브젝트이다.

- 정점 서술자 : 정점을 드로우 콜 과정에서 명령 대기열에 전달하고자 할 때 정점의 데이터 구조체는 연속된 형태인 String으로 분해됨. 이를 기존 정점 데이터로 복원할 때 정점 서술자를 통해 데이터를 조립한다.

- 버텍스 셰이더

- 프래그먼트 셰이더

 

2. 드로우 콜 생성

(1) 드로우 콜이란?

- 드로우 콜은 오브젝트를 한 번 그리는데 필요한 명령들의 묶음이다.

- 예를 들어 삼각형을 구성하는 정점 3개가 존재한다고 하자. 삼각형을 화면 상에 표현하고자 할 때 필요한 명령이 있을 것이다. 삼각형을 한 번 그릴 때 렌더 상태 생성하기, 버텍스 데이터 설정하기, 그리기 명령하기가 필요하다고 치자. 그러면 3개의 명령을 묶은 것이 삼각형에 대한 드로우 콜이 된다.

(2) 드로우 콜 생성

- 커맨드 버퍼에 GPU에 전달할 명령을 추가하는 일이다.

- 예시로 위에서 삼각형을 그리기 위한 드로우 콜이 커맨드 버퍼에 저장된다.

- 커맨드 버퍼는 명령 대기열에 추가되어서, 렌더링 파이프라인에서 GPU에 전달될 것이다.

3. 렌더링 파이프라인

(1) 정점 조립

명령 대기열에 있는 데이터는 연속된 데이터 열로 저장된다. 이 데이터들을 정점 구조체로 조립하는 과정이다. 구조체로 만들면 다른 파이프라인에서 정점을 보다 다루기 쉬워진다.

(2) 버텍스 셰이더

행렬 변환을 통해 모델로 존재하는 정점들을 카메라 상의 정점으로 변환한다. 모델 행렬, 뷰 행렬, 투영 행렬 간의 변환을 거쳐서 클립 공간(Clip space)으로 변환한다. 클립 공간은 카메라 상에 물체의 위치를 정규화하여 나타낸 것으로, 2x2x1의 직육면체 공간이다. x, y 값은 -1~1로 카메라 상의 위치를 나타내고, z는 0~1로 깊이를 나타낸다.

(3) 래스터 변환(Rasterization)

화면에 보이기 직전의 화소로 변환하는 과정이다. 뷰포트 변환, 프래그먼트 생성, 정점 간의 값 보간으로 이루어진다.

(4) 프래그먼트 셰이더

래스터 변환에서 생성된 프래그먼트에 어떤 색을 채울지 결정한다. 래스터 변환에서 전달하는 점 하나하나를 칠한다고 보면 된다. 컬러 값과 깊이 값을 결과로 내보낸다. 두 물체가 같은 위치에 있을 때, 깊이 값을 통해 멀리 있는 물체가 가려지게 한다.

 

 

 

 

참고 자료

OpenGL로 배우는 3차원 컴퓨터 그래픽스, 주우석 지음, 2013년 7월 30일 출간.

https://ko.wikipedia.org/wiki/%EA%B7%B8%EB%9E%98%ED%94%BD%EC%8A%A4_%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8

https://ko.wikipedia.org/wiki/%EB%9E%98%EC%8A%A4%ED%84%B0_%EA%B7%B8%EB%9E%98%ED%94%BD%EC%8A%A4

https://en.wikipedia.org/wiki/Graphics_pipeline

https://www.khronos.org/opengl/wiki/Vertex_Shader

https://www.khronos.org/opengl/wiki/Fragment_Shader, https://stackoverrun.com/ko/q/1047808

https://www.khronos.org/opengl/wiki/Compute_Shader

https://acatistory.tistory.com/51

댓글