타임라인은 유니티에 기본적으로 깔려 있는 패키지이다. 이 타임라인이라는 것을 사용하기 위해서, Cinemachine을 추가로 설치해 놓는 것이 좋다. Cinemachine을 추가로 설치하고 기능을 사용해보자.
아래와 같이 보스 몬스터가 있고, 플레이어가 트리거 영역에 들어서면 보스 몬스터의 애니메이션이 출력되는 상황을 만든다고 해 보자. 이를 세팅하기 위해 처음 만들어야 하는 것은 Timeline이다.
Inspector에 타임라인을 담을 빈 오브젝트를 만들고, Project에서 Timeline을 만들어보자.
타임라인을 생성하면 아래와 같은 아이콘이 생성된다.
타임라인을 누르고 빈 오브젝트를 누르면 새로운 타임라인을 만들 수 있다고 뜬다. 새 타임라인 만들기를 눌러보자.
이와 같이 동영상을 만들 때 쓰는 것 같은 창이 뜨며, 편집할 수 있는 저 공간을 트랙이라고 한다.
트랙에서 생성할 수 있는 것은 다양한 것들이 있다. 여기서 몇 가지 기능을 간단히 설명하자면 아래와 같다.
지금의 보스 등장 장면 연출을 위해 Animation Track, Signal Track, Cinemachine Track을 사용할 것이다.
이와 같이 생성하였고 시네머신은 메인 카메라를 기준으로 Virtual Camera의 전환을 넣었다.
애니메이션은 워록을 넣고 애니메이션 클립을 넣을 수 있기에 애니메이션 클립을 삽입하였다.
여기서 타임라인의 강점이 드러나는 것이, 카메라 전환이나 애니메이션 전환에 있어서도 보간이 들어가기 때문에 자연스러운 연출에 활용할 수 있다.
시그널은 Project에서 생성할 수 있으며 타임라인의 시작과 끝에 적용할 수 있는 시그널을 넣었다.
이후 플레이어에게 Signal Receiver를 삽입한다.
Signal Receiver의 목적은 보스 몬스터 등장 애니메이션 도중 플레이어가 움직이는 게 부자연스럽기 때문에, 그 동안의 움직임을 막기 위해 설정한 것이다.
이와 같이 세팅한 후 트리거 영역에 캐릭터가 들어가면 아래와 같이 연출이 이루어진다.
랜더링 파이프라인은 위와 같이 크게 5단계의 과정을 거치는 것을 표준으로 사용하고 있다. 이와 같은 그래픽의 표현 과정은 그리팩 하드웨어 장치(GPU)에서 수행되어 모니터로 출력된다.
입력 조립은 아래와 같은 과정으로 진행된다.
CPU는 메쉬를 그리기 위해 필요한 정점들의 정보를 정점버퍼(직렬화된 배열) 형태로 CPU에 전달한다.
정점버퍼를 전달받은 GPU는 정점 서술자에 정의된 규칙으로 정점 데이터로 조립하며, 다른 파이프라인 단계에서 사용할 수 있도록 삼각형과 같은 기본 도형으로 조립한다.
입력 조립 과정으로 만들어진 정점 데이터를 공간 데이터로 변환한다. (3D 공간 상의 정점 -> 클립 공간 상의 정점)
공간 변환은 행렬 연산을 통해 이루어지며, 변환 행렬은 총 3가지로 [Model], [View], [Projection]이 있다.
모델 공간을 월드 공간으로 변환한다. (Model Space -> World Space)
각 모델은 자신의 기준 위치를 원점(0, 0, 0)으로 하는 좌표 공간을 가지고 있으며,
월드 공간상의 좌표로 통합하는 과정을 거친다.
이 과정에서 이동(Translate), 회전(Rotate), 크기(Scale) 변환이 이루어진다.
월드 공간을 뷰 공간으로 변환한다. (World Space -> View Space)
카메라 공간은 카메라의 위치가 원점(0, 0, 0)이며, 카메라가 바라보는 방향이 +Z축인 공간 뷰 변환으로 모든 모델을 화면에 그려내기 쉽도록 카메라 기준으로 공간을 변환한다.
뷰 공간을 투영 공간으로 변환한다. (View Space -> Projection Space)
카메라 기준 정점의 위치를 화면에 보이기 위한 정점 위치로 변환한다.
화면에 렌더링 될 수 있는 영역을 나타내는 절두체(Frustum)가 정의되며,
원근감이 없는 직교 투영(Orthographic) 또는 원근감이 있는 원근 투영(Perspective)으로 진행된다.
정점 셰이더의 공간 변환은 많은 행렬 연산 단계가 필요하지만 결합법칙을 이용하여 단계를 축소할 수 있다.
공간 변환에 필요한 행렬끼리 곱한 결과를 정점 행렬과 곱하는 경우 연산 단계를 줄일 수 있다.
정점 데이터의 프래그먼트(Fragment)의 구성, 화면에 출력할 픽셀을 구성하는 단계이다
그래픽 하드웨어의 자체 알고리즘으로 동작하며, 프로그래밍이 불가능한 고정 파이프라인 단계이다.
레스터라이저 단계를 거쳐 기본도형은 픽셀로 변환되며, 각 정점을 기준으로 보간이 진행된다.
절두체 영역에 포함되지 않은 기본 영역을 처리하는 단계이다.
기본 도형 중 랜더링이 되지 않는 후면을 찾아내 제거하는 단계이다.
View 벡터와 기본 도형의 Normal 벡터의 내적을 계산해 후면을 확인한다.
3D NDC 공간 상의 좌표를 2D 스크린 좌표로 변환하는 단계이다.
-1 ~ 1 범위였던 (x, y) 좌표를 화면 해상도 범위로 변환한다.
기본도형을 통해 프래그먼트를 생성하고, 프래그먼트를 채우는 픽셀들을 찾아내는 단계이다
각 픽셀마다 정점 데이터(위치, 색상, 법선, UV)들을 보간하여 할당한다.
(안티 앨리어싱)
래스터라이저 단계에서 구해진 기본 도형의 픽셀에 투명도, 조몽과 그림자, 텍스쳐 색상을 입히는 단계이다.
화면을 구성하는 기본 도형을 구성하는 각 픽셀마다 픽셀 셰이더를 한 번씩 호출한다.
픽셀 데이터(깊이 값, 색상 값)을 계산해 다음 단계로 전달한다.
기본 도형의 질감을 표현하는 이미지이다.
텍스쳐가 매핑되어 있는 UV 좌표를 사용하여 기본 도형의 그려질 픽셀에 색상을 추가한다.
표면의 법선을 표현하는 방법이다
텍스쳐와 같이 UV값을 통해 매핑되며 각 픽셀의 값으로 표면 벡터를 구성한다.
표면 벡터의 값을 통해 조명 및 그림자 표현을 진행하여 표면의 각도를 추가한다.
RGB로 법선 벡트의 값을 표현하기 때문에 일반적으로 푸른 색조를 띄게 된다.
표면의 돌출부와 윤곽을 더 선명하게 하는데 사용한다.
가시적은 표면 텍스쳐 영역을 실제로 이동시켜 표면의 높낮이를 조절한다.
카메라에 가까운 쪽은 확대 및 강조되고, 카메라에서 먼 쪽은 축소되어 가려진 것처럼 보이게 한다.
흰색 영역이 텍스쳐의 높은 영역을 나타낸다.
* 연산이 많이 무거워 많이 사용하는 추세는 아니다.
조명은 광원의 위치부터 기본 도형에 반사된 빛이 카메라에 들어오는 비율을 계산해 구현한다.
입사각 벡터를 기본 도형 법선 벡터와 연산하여 반사각 벡터를 구하고, 반사각 벡터와 카메라의 위치 벡터 사이의 내적의 값으로 비율을 구할 수 있다.
표시되는 픽셀을 결정하고 최종 픽셀 색을 혼합하기 위한 단계이다.
각 픽셀의 위치마다 여러 기본 도형의 픽셀이 겹쳐 있을 수 있으며, 이 겹치는 픽셀들을 판단 및 연산하여 픽셀의 최종적인 색상을 결정한다.
픽셀이 다른 픽셀보다 앞에 있는지 판정하기 위해 사용하는 기법이다.
장면의 물체를 먼 것부터 가까운 것 순서로 그리기 위해 사용한다.
깊이 버퍼를 이용하여 물체들을 그리는 순서대로 그려 다른 물체를 가리게 한다.
픽셀은 투명을 표현할 방법이 없기 때문에 뒤에 표현될 오브젝트의 색상을 섞는 방식으로 투명도를 표현한다.
오브젝트의 픽셀을 화면에 그리거나 그리지 않도록 판단하기 위한 마스크 용도로 사용한다.
픽셀 데이터의 스텐실 버퍼를 통해 동작하며, 각 픽셀의 표현 단계에서 스텐실의 값을 비교해 표현 여부를 결정하는데 이용할 수 있다.
URP의 사용 방법에 대한 내용은 메뉴얼에도 상세하게 나와 있으며, 따로 공부해 볼 여지가 있다.
URP를 사용해보기 위해 프로젝트를 만들어 보자.
프로젝트의 생성 단계에서 보면, Built-In으로 생성하거나 Universal로 생성하는 방식이 있다.
여기에서 URP를 사용하기 위해선 Universal 2D 나 3D로 생성해주면 된다.
Built-In에서 추가로 패키지를 설치하여 URP로 전환하는 방식도 있지만, 왠만하먼 프로젝트 생성 단계에서 URP를 사용할 건지 결정하고 미리 URP 프로젝트로 생성해 놓는 편이 좋다. 설정을 바꾸면 프로젝트 진행 과정 중 Material이 깨지는 등 문제가 발생할 수 있기 때문이다.
다만 이 세팅도 일일히 설정을 다 하면 복구할 수 있긴 하다. 이와 같은 불편함이 발생하지 않도록 계획 단계에서 URP 사용 여부를 결정하도록 하자.
그러면 URP프로젝트를 생성해보자.
3D의 경우 URP 탬플릿이 기본적으로 다운받아져 있지 않기 때문에 다운을 받고 프로젝트를 생성해보자.
프로젝트를 생성하면 기본적으로 제공되는 파일 구성이 약간 다르다는 것을 알 수 있다.
URP에서의 카메라는 인스펙터 내용이 조금 다름을 알 수 있다.
URP에서의 Material은 Built=in 의 Material과 다르다. 그래서 호환이 되지 않는 부분도 있으며 특징적인 부분이 있다.
URP의 Material 형식은 보통 Lit과 Unlit을 사용한다. 둘의 차이는 Unlit은 색에 대한 정보만 있어 원근감이나 굴곡감이 없다는 특징이 있다.
Built-in 에도 있는 설정인데 효과는 아래와 같다.
Metallic : Metal 같은 재질감
Smoothness : 표면 매끄러움 정도 - 수치가 클 수록 반사율 높음
Transparent라는 설정을 할 수 있다.
Transparent 설정을 하게 되면 오브젝트의 투명도를 만들어 줄 수 있다. 다만 유의할 것은 투명도를 굳이 사용하지 않는 오브젝트에서도 투명도 연산이 발생하므로 투명도를 사용하지 않을 경우 이 옵션을 해제해줘야 한다.
벽 뒤의 플레이어가 실루엣으로 투과되어 보이는 기능을 만들어보자.
위와 같이 맵을 세팅한 후 SilhouetteRenderer를 만들어보자.
해당 렌더러를 만든 후 URP-High Fidelity에 실루엣렌더러를 추가해주자.
이제 메인카메라로 돌아가면 Renderer를 선택할 수 있고, 여기서 SilhouetteRenderer를 선택해준다.
다음으로 SilhouetteRenderer에서 Add Rederer Feature로 Render Object를 선택한 후, 아래와 같이 세팅한다.
이와 같이 만든 후 아래와 같이 출력되는 것을 확인할 수 있다.
URP가 적용된 프로젝트에서 PostProcessing이라는 기능을 사용할 수 있다.
이는 출력된 화면에 추가적으로 효과를 줄 수 있는 기능이다.
기본적으로 생성되어 있는 Global Volume에 New로 새로운 프로필을 생성해보자. 임시로 TempFile이라 만들었다.
해당 효과를 살펴보기 위해 우선 임시로 오브젝트를 만들어보자.
형광색으로 빛나는 물체를 배치하고 Bloom의 효과를 살펴보자.
이와 같이 효과를 줄 수 있다.
(눈갱 조심)
RGB 분리 잔상효과를 준다.
치지직 거리는 효과를 준다.
텍스쳐를 입혀서 원하는 효과를 줄 수도 있다.
가장자리를 원하는 색깔로 만드는 효과를 준다.
렌즈 왜곡 효과를 줄 수 있다.
화면에 칙칙한 효과를 준다. 빛도 영향을 받으니 분위기에 활용할 수도 있다.
일반
ACES
퍼지는 듯한 조명 효과를 줄 수 있다.
Spot Light와 달리 구 형태의 조명이다.
조명을 만들고 있을 때 이와 같이 그림자가 없는 상황을 보통 기본 설정으로 되어 있다. 하지만 그림자 효과를 주고 싶을 경우 해당 옵션을 체크해주면 된다.
No Shadow
Hard Shadow
다만 그림자와 같은 효과를 넣을 경우 실시간으로 연산을 계속해야 하기 때문에 광원이 많은 경우 게임 성능 저하의 가능성이 발생할 수 있다.
이를 방지하기 위해서 광원의 효과가 필요한 오브젝트만 Static으로 설정한다.
Plane과 벽을 Static으로 만든 후 씬 창에서 Baked Lightmap으로 전환한다.
그러면 이와 같이 Static으로 설정한 오브젝트만 표시가 되고, 빛이 전부 설정된 상태로 bake를 하면 된다.
(Lighting은 Window로 옵션을 열고 실행)
그러면 위와 같이 빛이 설정된 상태로 맵이 구워지게 되고, 여기서 보이는 광원은 연산이 들어가지 않은 광원이 된다.
Light Probe Group을 사용해보자.
이는 위와 같이 노란색 공들을 광원이라고 생각하고, 그 안에 오브젝트가 들어왔을 때 마치 광원을 받는 것처럼 효과를 줄 수 있도록 하는 기능이다.
편집 기능을 누른 채로 구체를 배치한 후 맵을 다시 구워보자.
(구체 복사 키는 Ctrl+D)
맵을 다시 구운 뒤 오브젝트를 안에 넣어보면, 위치에 따라서 플레이어에게도 조명이 들어오는 것을 확인할 수 있다.
동적 오브젝트에게 빛 효과가 필요하면 효과를 쓰고, 필요 없으면 안 쓰는 식으로 효과를 조절해야 한다.
Shadowmask : 정적, 동적에서 모두 자연스러운 빛 효과
Substractive : 주광에 대해서만 연산 진행
Baked Indirect : 중간 단계
빛 또한 각각의 옵션이 있으며, Realtime과 같이 연산이 많이 필요한 경우와 Mixed, Baked와 같이 옵션이 있으며 효율을 생각하는 빛 연산 방식에 대해 고민이 필요해 보인다.