본문 바로가기
Unity/Base

Unity 카메라 워크 ( Camera Work )

by Pretty Garbage 2022. 3. 8.

 

요 근래 이렇게 포스팅을 열심히 한적이 있나 싶긴 합니다만 간만에 책을 구매한 김에 공부하면서 후임자들이나 기타 처음 접하는 사람들에게 정보를 공유할 겸 포스팅이라도 열심히... 작성하자 생각했습니다. 언제까지 가련지는 모르겠습니다만... 어쨌든!

책은 Unity Game 프로그래밍 바이블 2nd 개정판을 기반으로 하고 있으며, 일본 원서를 참고로 기술해나가고 있습니다. 아마 Base 카테고리의 글들은 대부분 이 책을 기반으로 진도를 나갈 예정이며, 계속 포스팅에 이 내용을 적도록 하겠습니다.

 

 

카메라 작업에 관하여 설명하고자 합니다. 

 

Unity에서 사용하는 카메라 컴포넌트에 대한 이야기를 하는 것과 동시에 기본적인 카메라 워크에 대해서도 이야기하고자합니다.

그리고 새로운 버전에서(기존부터 있던건가...) 시네마신에 관해서도 이야기하고자 합니다.

 

유니티는 카메라의 시야각에 잡히는 영역을 렌더하게 됩니다. 사실 이 것은 영화나 애니메이션 등 연출을 기반으로 한 모든 영역에 관여하게 되는데 실제로 촬영장에 카메라가 돌고 있다라고 생각하시면 편합니다. 어쨌든 촬영장이 부산하든 뭐하든 시청자들한테 보여지는 것은 카메라에 담겨져서 편집되어지는 내용들이지요. 그리고 이 움직임을 얼마나 잘 다루고 표현하냐에 따라서 같은 내용이라도 더 화려하거나 있어보이게 만들어주기도 합니다.

 

우선 카메라 컴포넌트에 관해서 입니다.

 

1. 카메라 객체 만들기

 

새 장면을 만들 때 기본적으로 Main Camera 와 Directional Light의 객체가 씬의 하이라키에 배치되어있습니다.

Main Camera는 카메라 컴포넌트를 갖고 있으며 반드시 한개 이상의 카메라는 씬에 존재해야 실제 프로그램에서 렌더를 할 수 있게 됩니다.

 

실제 촬영장에서 여러대의 카메라를 두고 촬영하고 편집하듯이 유니티 내부에서도 여러대의 카메라를 둘 수 있습니다. 실제로 '렌더 텍스처'라는 기능을 활용할 때에 촬영하고 싶은 영역에 카메라를 두고 사용하기도 합니다.

 

2. 카메라 컴포넌트의 기능

 

사실 카메라의 컴포넌트 내용물은 현재 자신이 어떤 렌더링 파이프라인을 사용하는가? 에 따라 다릅니다. 

일단 build-in 기준으로 기술해나갑니다.

 

유니티 2021.3.14 기준으로 알려드립니다. (포스팅 작성 기준 제일 최신이었습니다... 실리콘 지원버전중)

 

Built In

 

Clear Flags : 그려지지 않는 범위에 대해서 어떻게 처리할지에 대한 내용입니다.

- Skybox = 기본 설정으로 된 스카이박스를 이용해서 처리한다. (스카이박스 내용물은 수정이 가능합니다.)

- Solid Color = 사용자가 지정한 색으로 그려지지 않는 범위에 대해서 처리해버립니다.

- Depth Only = 빈공간을 투명처리합니다. 기본적으로는! 주로 복수의 카메라를 이용할 때 활용하는데 컬링 마스크를 통해 구분지어 놓고

Depth에 의해서 차곡 차곡 쌓이면서 필요한 두개의 정보가 보여진다거나 하는 연출을 실현할 수 있습니다. 

- Don't Clear = 클리어하지 않는다. 그래서 잔상효과나 이런 것들이 남겨져서 그려지는데... 사용한 적이 별로 없네요.

 

Background : skybox에서는 어떤 효과를 일으키는지는 모르겠습니다만 solid color에서는 지정한 색으로 빈공간이 채워지게 됩니다.

 

Culling Mask : 카메라에 표시될 레이어를 지정합니다. 선택한 레이어만 카메라에서 노출되어지게 됩니다. 기본적으로 Everything으로

설정되어있는데 미니맵이라던가 다른 렌더 텍스처들을 이용할때 사용하시게 됩니다. Cull이라는 뜻이 추려내다. 라고 합니다.

 

Projection : 장면에서 객체를 투영하는 방법

- Perspective = 간단하게 원근감 표현 방식

- Orthographic = 평행 투영법 거리에 관계없이 균일하게 표현 2d게임에 어울림.

 

Size : Orthographic을 선택했을때 활성화됩니다. 카메라의 뷰포인트 사이즈를 결정합니다. 사이즈의 값이 작을수록 오브젝트가 더 크게 표현됩니다.

 

FOV Axis : Perspective를 선택했을때 활성화됩니다. 아래 항목인 field of view에 의해서 계산에 사용하는 축을 정합니다. 

 

Field of view : 시야각이라고 정리 가능. 값이 작을수록 화면에서 보이는 범위가 좁아지고 객체들이 상대적으로 크게 비춰집니다.

 

Physical Camera : 실제 카메라를 시뮬레이팅 가능합니다. 누르시면 센서타입 센서 사이즈 등등 설정 가능합니다. 피지컬 카메라 옵션은 기술하지 않습니다.

 

Clipping Planes : Near는 카메라로부터 최초로 렌더링하는 범위의 시작점 Far는 렌더링영역의 마지막이라고 보시면 됩니다. 렌더링을 해야할 오브젝트가 카메라기준 저 영역에 포함되어있지 않다면 렌더하지 않습니다.

 

Viewport Rect : 카메라가 그리는 사각 영역에 대한 정보입니다. x와 y는 x축과 y축에 대한 정보이고 w는 너비 h는 높이에 대한 정보입니다.

 

Depth : 위에서 이야기한 Clear Flag에서 Depth Only에 관련된 설정값으로 카메라의 렌더링이 되는 중첩 순서에 관련한 값입니다.

 

Rendering Path : 카메라가 이미지를 렌더링하는 방법을 선택하는 항목입니다.

- Use Graphic Settings = 유저가 세팅한 그 세팅대로 갖다가 씁니다.

- Forward = 너무 기술해야할 내용이 많고 필자도 자세히 알고 있다라고 말하기 어렵기 때문에 간단히 설명하자면 전통적인 방식이며 유니티에서 대부분 지원합니다. 다만 화면에 렌더링이 되지 않아도 되는 면도 셰이딩 연산을 해야하고 라이트 증가가 되면 계산의 복잡해지기 때문에 실시간 라이팅 연산에 부적합하다 정도로 정리하고

- Deferred = 라이팅 계산을 먼저 하지 않고 나중에 계산하기 때문에 Deferred 라고 부르며 라이팅을 위한 계산이 O(1) 복잡도를 갖게 된다. 즉 오브젝트가 몇개가 놓여있든 상관이 없다. 다만 반투명의 오브젝트나 하드웨어 안티 얼라이어싱을 지원하지 않는다는 제한도 있다. 

또한 평행 투영 포트가 없기 때문에 Orthographic에서는 Forward로 ㄱㄱ

-Legacy Vertex = 정점 라이팅에 의한 렌더링을 실시한다. 모든 조명에서 주제별로 계산하기 위해 가장 빠른 렌더링 방식이지만 픽셀 단위로 수행되는 그림자, 노멀 맵, 라이트 쿠키 등의 효과는 지원되지 않습니다.

-Legacy Deferred = 위에 디퍼드와 비슷합니다. 표준 셰이더 및 반사 프로브와 같은 기능을 지원하지 않기 때문에, 새로운 프로젝트에서는 디퍼드 쉐이딩에 의한 렌더링을 사용 권장합니다.

 

Target Texture : 카메라에서 촬영한 이미지가 참조되어질 타겟 텍스쳐를 설정합니다. 렌더 텍스쳐 이용시에 사용됩니다.

 

Occlusioin Culling : 쉽게 말하면... 렌더링이 되지 않는 영역은 그려내기 위해 연산하지 않는다. 안보이는 영역에 대해서 그려내고 쉐이딩 연산 이런 것들이 안들어가기 때문에 최적화쪽 기능이다.

 

HDR : 요즘 이기능에 대해서는 많이들 아실 것이라 생각되는데 가장 밝음으로 부터 가장 어두움까지의 범위를 DR(Dynamic Range)라고 하는데 밝은 곳은 더 밝게 어두운 곳은 더 어둡게 만들어 사람이 실제 눈으로 보는 것과 가깝게 만드는 옵션입니다.

 

MSAA: 멀티 샘플링 안티 알리아싱의 약자입니다. ssaa처럼 서브 픽셀증가 시켜서 계단현상을 줄이는 옵션인데 알고리즘이 다르다고합니다. 비디오 메모리 사용량이 커지고 위에서 말했듯 deferred에서는 사용할 수 없습니다. 

 

Allow Dynamic Resolution : 동적 해상도 조절을 허용할 것인가의 옵션입니다. 앱은 부하가 걸리면 해상도를 동적으로 변경하여 프레임 속도를 유지합니다.

 

Target Display : 보여질 디스플레이를 뜻합니다.

 

 

URP

 

Render Type : 필드에서 Base와 Overlay를 선택합니다.

Base 카메라는 URP의 디폴트 타입의 카메라로, 장면내의 오브젝트를 렌더하는데 사용됩니다. Overlay타입 카메라는 다른 카메라 출력위에 뷰를 렌더링 하는 방식입니다. 2d UI와 3D오브젝트를 중첩되서 그려낼 수 있다곤 하는데 사용해본 적은 없습니다. 

 

Projection : 다른 렌더링 파이프라인과 공통 항목들이 나열되어 있습니다. 위에서 설명했기 때문에 넘깁니다.

 

Rendering - Renderer : 카메라 오브젝트의 사용하는 렌더러 방식을 설정합니다. 렌더러 방식도 위에 설명했습니다.

Rendering - Post Processing : 체크하면 포스트 프로세싱이 활성화됩니다.

Rendering - Render Shadows : 체크하면 그림자를 그려냅니다.

Rendering - Opaque Texture : CameraOpaqueTexture를 생성할지 여부를 설정합니다. 아마 자세히는 모르겠지만 쉐이더 그래프에 레퍼런스할 리소스로 추가가 되는 것 같습니다.

Rendering - Depth Texture : 아마 이것도 쉐이더 그래프에 리소스로 추가할 수 있도록 활성화시키는게 아닌가 싶습니다. 카메라에서 본 깊이 정보를 전달합니다.

 

Environment - VolumeTrigger : HDRP의 Volume Anchor Override와 비슷한 기능인 것 같은데 앵커가 되는 게임 오브젝트의 트랜스폼을 할당하면 게임 오브젝트가 다른 Volume영역으로 진입시 해당 볼륨에 적용되어있는 포스트 프로세싱이 적용됩니다. 할당되지 않은 경우 카메라 자체의 트랜스폼 값이 사용됩니다.

 

Output - 역시 공통항목입니다.

 

Stack - Overlay카메라들을 추가해서 장면을 렌더링할 때에 스택의 순서대로 그려냅니다.

 

 

카메라 워크 의 종류

 

픽스 카메라를 고정시켜서 촬영
팬 (일어 원어라서 빵이라고 써져있길래 뭔가했음) 카메라를 수평 방향으로 회전시켜 촬영
틸트 카메라를 수직 방향으로 회전시켜 촬영
렌즈의 초점 거리를 바꾸어 FOV를 변화시켜 촬영 확대 / 축소
포커스 초첨이 맞는 점을 바꾸어 촬영 포커스 인이나 포커스 아웃 등
트래킹 움직이는 피사체에 대하여 카메라를 따라가게 해서 촬영
돌리 카메라 자체를 움직여 피사체에 접근하거나 피사체에서 멀리하여 촬영

 

픽스 : 카메라를 고정하고 촬영하는 카메라워크입니다. 촬영의 기본이라고도 불리는 카메라 작업입니다. 

: 1인칭 게임을 할때 마우스로 좌우로 움직이게 되면 상대방 오브젝트는 가만히 있고 좌우로 움직이는게 이게 패닝입니다.

틸트 : 1인칭 게임시에 마우스를 상하로 움직이게 되면 고개를 끄덕이는 효과처럼 보이는데 이것이 틸트

: 줌인 줌아웃이야 너무 잘알테니 패스

포커스 : 피사체에 포커스를 맞추어서 주변 오브젝트들을 날리는 효과입니다. 피사체에 포커싱을 맞추면 해당 오브젝트에 집중되어지고 뒷 배경이 날라가니 좀더 집중되는 효과를 줍니다.

트래킹 : 피사체를 추적하면서 쫓아가며 촬영합니다. 피사체의 Translate를 따라간다고 생각하면 되고 비슷한 개념으로 팔로우 카메라는

카메라는 그자리에 고정이지만 피사체를 따라서 로테이션 값만 변하며 에임을 쫓는다 정도로 이해하고 있습니다.

돌리 : 달리 라고하나? 여튼 대학생때 동아리 이름이 돌리라서... 그냥 돌리 여튼 이 개념을 이해하기 좀 어려웠는데 줌이랑 비슷한거 같다가도 트래킹의 일종이라고도 하는데 여튼 돌리 인 돌리 아웃의 경우에는 줌인 줌아웃은 고정된 포지션에서 배율을 변경해서 확대하거나 축소한다면은 돌리 인 돌리 아웃은 실제로 레일 위에서 서서히 가까워지고 서서히 멀어지는 연출이 가능하게끔 한다. 돌리는 그냥 그 레일위에 그 시스템 자체를 말하는 듯 하다.

 

[Scripts]

 

Fix 카메라 여러 방면에서 피사체를 촬영할 때의 카메라 스위처

	//각각의 카메라 오브젝트를 미리 설치해놓는다.
    [SerializeField] private List<GameObject> cameraList;

    private GameObject prevCamGameObject;

    private void Awake()
    {
        //디폴트 카메라를 세팅한다.
        prevCamGameObject = cameraList[0];
    }

    /// <summary>
    /// 카메라 아이디를 매개변수로 넘겨 해당 오브젝트를 켠다.
    /// </summary>
    /// <param name="camId"></param>
    public void OnChangeCamera(int camId)
    {
        //매개변수로 넘어오는 인자가 리스트의 범위밖이면 리턴 safety code
        if (camId < 0 || camId >= cameraList.Count) return;

        for (int i = 0; i < cameraList.Count; i++)
            cameraList[i].SetActive(i == camId);
        //위 방식이 맘에 들지 않는다면 전역변수에 prevCam을 하나 임시로 저장해두고
        //prevCamGameObject.SetActive(false);
        //cameraList[camId].SetActive(true);
    }

 

카메라 패닝은 카메라의 로테이션 값을 일정 값만큼 수평으로 움직여주면 된다. 틸트도 다만 여기서 중요한 포인트라면

 

틸트 기준으로 첨부합니다.

	float rate = Mathf.Clamp01(elapsedTime / tiltTime);
        
        Quaternion rotation = Quaternion.Slerp(이전로테이션, 목표로테이션, rate);
        camera.transform.localRotation = rotation;

업데이트 함수에서 돌리든 코루틴 반복문으로 돌리든 아니면 unirx에 맞게 변형해서 쓰든 이 로직이 도움이 될터인데 

Clamp01은 강제로 0과 1사이의 비율로 집어넣는 함수이다. 비율의 값으로 변수에 저장해서

Slerp로 구면 선형 보간을 해주면 조금더 괜찮게 연출되어짐을 알 수 있다. (Lerp는 선형 보간)

 

위와 비슷한 방식으로 줌인 줌아웃도 정해지는데 이때 카메라의 포지션 값을 조정하는게 아니라 카메라의 fov를 조정한다.

 

트래킹이나 팔로우 카메라는 사실 방식이 여러개지만 오브젝트 하위에 카메라를 박아넣어도 되고 오브젝트의 트랜스폼 정보를 받아와서 동기화 시켜줘도 된다. 팔로우 카메라의 경우에는 그냥 Update에서 LookAt처리로도 간단히 구현이 가능하다.

 

카메라 포커싱은 포스트 프로세스를 이용하는 방식인데 Post-process Volume에 

Depth of field의 Focus Distance를 이용해서 거리조절을해서 포커스를 맞추는 방식이다.

 

저 포커스 디스턴스를 조절하면 흐려졌다가 선명해졌다가- 저걸 지원하는 프로필을 만들어야한다. 

Create -> Post Processing profile -> 인스펙터에서 Add Effect의 Depth of Field를 추가해주자!

 

 

정리하며

 

매번 블로그 포스팅에 정리하다보면... 시간이 4시간이고 5시간이고 가는데 이렇게 정리하면서 아 대충 알아 이러고 지나가는 것들에 대해서 한번 더 보고 정리할 수 있었던 기회가 되는 것 같습니다. 사실 최근에는 Unity의 시네마씬이라는 기능이 추가되면서 더 자연스럽고 다양하고 강력한 기능들을 선보일 수 있는 것 같은데 향후 공부하고나서 포스팅하도록 하겠습니다.