3인칭 캐릭터 만들어보기 3# 카메라궤도(자유시점) 만들어보기 (FreeLook 만들어보기)
기존에 캐릭터 이동+회전 그리고
캐릭터를 따라다니면서 회전도 같이 하는 카메라까지 만들었었다
이번엔 3인칭 게임에서 종종 프리룩이라부르는
자유시점 카메라 기능을 만들려 한다
다른 게임들을 보면 자유시점이 약간씩 차이가 있겠지만
바라볼 대상(캐릭터를)을 중심으로 회전을 하는 공통점이 있었다
사실 카메라를 캐릭터 자식오브젝트로 두고 하면 엄청 편하지만
내가 이번에 만들어왔던건 그런것없이 하이어아키창에 독립적으로 사용하는걸 목표로했었다
그래서 약간 귀찮아진점이 있는거같다;
1. 캐릭터 중심으로 원형태로 돌게 만들어보기
원의 특징은 반지름길이R만큼 곱해진
(Cosθ , Sinθ , 1) 벡터로 그 형태를 그리고 있는걸 알수있다
cos과sin 그래프를 합치어서 보면
위 그림과 같다
반지름은 저 xy값에 스칼라배한것이란 의미가 된다
먼저 center변수는 카메라가 위치를 원형태로 그리기 위한 중심점, 즉 현재 캐릭터 위치가 된다
그러면 원의 반지름, 즉 카메라가 캐릭터를 얼마나 둘지는
전에 만들어두었던 변수 _camDistance를 그대로 곱하여 사용하면 좋겠다 싶었다
그리고 horMove라는 변수도 만들었는데
마우스X입력값을 저장해두었다 이어서 작업을 하려했다
(코사인 사인함수에 매프레임마다 새값을 넣으면 원형태로 돌수없다)
그후 마우스를 이동할떄 (Input.GetAxis("Mouse X")) 원형태로 cos sin함수에 해당 마우스 이동값에 축적되어
원을 그리며 동그랗게 이동하는게 완성이 되었고
추가로 캐릭터 대상을 바라보게 회전값을 수정하는일이 생겼다
(그냥.. 카메라를 자식객체로 두면 엄청편할텐데 말이다..)
center (캐릭터위치를 중심점으로 원형태로 위치할 내 카메라 위치값)
에서 y값을 뺴었다 (y값없이 xz값으로만 계산하고싶었다)
그리고 센터에서 캐릭터로 향하는 방향벡터를 만들고
모두 정규화 해준다(길이가 1이어야한다)
현재 카메라의 월드상 포워드벡터도 만들어 둘을 내적+외적하여
앞뒤판별 + 좌우판별까지 하였다
그후 외적Cross의 결과로 나온 벡터의 y값이 양수인지 음수인지를 판단하여
좌로 우로 회전마다 다른 값을 넣어주었다
그렇게 나온 회전값을 LateUpdate에서 직접 회전시킨다
업데이트문에선 줌상태 + 장애물판정 +
마우스 우클릭이 눌렸는지 if (Input.GetMouseButton(1) )
판정으로, _isLinearTr 멤버변수값을 바꾸고있다
_isLinearTr 변수는 bool형태인데
_isLinearTr의 값으로 회전할 방식을 LateUpdate에서 바꾸고 있다
위에 LateUpdate부분에서 직접 카메라의 이동+회전을 하는데
먼저 캐릭터가 이동+회전하면 카메라는 따라가게 기존에 만들어두었다
이때 Lerp함수를 사용해 약간의 딜레이를 주며 이동과 회전을 따라가게 만들었다
그러나 프리룩에선 천천히 따라가게 만들면 좀 답답한 모습이 나와서
Lerp함수로 천천히 보간하는 방식이 아닌 , 회전값을 rot으로 강제로 바꿔주는걸 선택했다
한번 플레이 해보기로했따
먼저 게임뷰에서 캐릭터를 앞으로 이동시키면서 우클릭(프리룩)으로
마우스 회전하며 돌려보고있다
빈도수는 낮지만, 중간에 지터링마냥 살짝 덜덜거리는 부분이 있는거같아
LateUpdate에서 회전을 하고 이동을 그 뒤로 미루어보았다
다시 플레이해보자 이번엔 완벽했으면 좋겠다..
훨씬 낫다, 큰 차이는 아니지만 내가 볼떄 엄청 부드러워졌다 (초반에 덜컹거리는 부분은, 편집을 잘못해서 나왔다)
이제 에디터 상에서 내가 그렸던 회전과 이동이 되는지 봐야한다
원을 그리며 이동하고, 회전도 언제나 대상을 바라보고있다
아 기분좋다 ㅠ 좌우 회전은 여기까지로 하려했는데
생각해보니
난 카메라의 위치를 잡으려 원형태로 이미 값을 만들어두었는데
회전을 하겠다고 변수를 또 여러개 만들고 추가적인 계산을 한것같았다
윗부분을 아래로 바꾸었다
코드가 훠얼씬 간결해지었다, 마찬가지로
작동은 동일하다
그렇다;; 난 바보였던 것이다 원의 형태로 이미 위치를 잘 잡았으면
그걸 이용해서 회전도 동시에 해버리면 훨씬 짧고 직관적으로 만들수있엇는데
왜 처음부터 회전을 만들어두려한것인가..
horMove에 -1 음수형태로 회전하는 이유는
카메라가 캐릭터의 왼쪽방향으로 돌면, 카메라의 시야는 오른쪽으로 반대로 돌게되는 구조라서다
그리고 -90f를 붙인건 일종의 offset 조정값이다
저 -90f를 안하면, 90도씩 틀어진채로 회전한다 정확한 이유는 아래에 설명했다
horMove변수는 언제나 마우스 입력값을 받아 저장해두는 멤버변수이다
단 프리룩을 안쓰면 값을 다시 초기화하는데
겟마우스버튼(1)은 우클릭을 누르고 있을때이다
한번이라도 안누르는 순가
horMove값이 -90*Mathf.Deg2Rad로 바뀐다
horMove값은 평소 라디안으로 사용한다
초기값이 " -90*Mathf.Deg2Rad"인 이유는
먼저 -90*Mathf.Deg2Rad은 라디안값이며, -(PI/2)가 된다
캐릭터로 부터 Mathf.Cos(-(PI/2)), 0,Mathf.Sin(-(PI/2))값은
(0,0,-1)이된다
프리룩 시점을 클릭시, 우리의 카메라가 캐릭터 뒷편에서 시작한단 의미가 된다
또 프리룩을 끄면 초기화되며, 언제나 다시 누르면 캐릭터 뒷편에서 프리룩이 시작된다
사실 내가 카메라 프리뷰를 캐릭터 뒤에서 시작하도록 만들고싶어 일부러 넣은값이다
또 horMove값으로 Mathf.Cos , Mathf.Sin함수의 인자에 넣어두어
마우스를 회전 시킬떄마다 캐릭터를 중심으로 돌면서 위치를 변화하고
원의 형태로 그린 값을 회전값에 반대로 두면 카메라도 동시에 회전을 하게된다!
처음에 내가 이걸 만들수있을까 고민했는데 얼추 모습이 나와 놀랐었다;;
이렇게 캐릭터를 중심으로 궤도를 형성하는 카메라 움직임과 회전을 만들었다(프리룩)
2. 카메라 줌인 아웃
카메라 줌인 아웃이다
_cam은 메인카메라를 참조하는 멤버변수이다
Camera.Main....으로 사용하려했는데 예전에
만약 메인카메라를 자주 호출한다면
메인카메라를 그떄마다 쓰기보다 참조해서 사용하게 좋다는 글을 과거에 본적이있다
그래서 참조하여 사용하기로했다(줌인아웃은 자주 사용할수도있을거같아서)
float scroll = -Input.GetAxis("Mouse ScrollWheel") * _scrollSpeed;
말그대로 스크롤 휠을 입력한값에 따라 스크롤량이 정해진다
스피드 조절을 위해 _scrollSpeed 변수를 곱해주며, 이 변수는 인스펙터에서 고칠수있게 했다
_cam.fieldOfView = Mathf.Clamp(_cam.fieldOfView + scroll, 33f, 90f);
카메라의 필드오브뷰 변화에 정해둔 스크롤값을 넣어주는데
단 멋대로 줌인아웃보단 범위안에서 하는게 맞을것이고
범위를 정하려면 Mathf.Clamp함수가 딱 알맞겠다 싶었다
gif가 살짝 뚝뚝 끈겨보이는거같아
실제론 부드럽게 잘된다
3. 위아래로 카메라 자유시점
먼저 캐릭터에서 카메라로 향하는 벡터와
캐릭터의 업벡터를 드로우레이를 이용해 보았다
저 각도를 이용해 위아래 카메라 회전도 표현할수있지 않을까 생각이 든다
최종이다 그런데 만들고 나서 든생각이
결국 구면좌표계와 데카르트좌표계 공식을 쓸거면
처음부터 그렇게 만들걸 싶었다
코드가 길진 않지만, 그래도 설명하기 상당히 힘들게 되었다
먼저 카메라 y 높이값은
원형태를 그리는 xz크기에 반비례하게 설정했다 (구모양 구조로 회전 + 이동한다고 생각하면 될것같다)
카메라가 캐릭터 위로 올라가면, 원형태를 그리는 xz값이 사실상 0에 가깝다
angle변수에 " 90f - "를 하는 이유는 내가 구한것이
양각(elevation)이 아니라, (90-양각)이라 저렇게 수동으로 직접 써주었던것이다
그런데 방금말했듯이 이렇게 작성할거면, 처음부터 구면좌표방식으로 만들고 새롭게 할걸그랬다
(나중에 다시 새로 만들어야겠다..)
horMove -> y축회전 좌우회전 입력값
vertMove -> x축회전 위아래 회전 입력값
그에따라 Mathf. 함수들로 위치가 조정된다
rot에는 최종적으로 카메라가 대상을 바라보도록 변해야할 회전값이 들어가게된다
단
rot = new Vector3(90f -angle*Mathf.Rad2Deg , -horMove * Mathf.Rad2Deg - 90f, 0);
일정 수치 조절한부분이 좀 있다
약간의 옾셋조정이다.. 설명하기가 힘들다.. 그냥 보기 편한구조로 만들지 못한
내 잘못이 큰거같다... 좀더 쉽고 간결하게 만들려 노력해야겠다
설명해야되는 사람이 설명을 못하면 어떻게 되는가..
구모양을 그리면서 회전하고있따 잘되었다..
x축회전 0~90도로 clamp시킨것도 잘 된거같다
얼추 완성이된거같다
아쉬운점은 프리룩기능을 아예 구형좌표계로 전부 통일시켜 수정을 다시 해봐야겠딴것이다
좀 지저분하게, 나만알아볼수있게 쓴거같아 역시 난..이런 생각만 드는 날이다
우선 오늘은 여기까지하고 다음엔 스크립트에 부족한 부분 보충및 내가 만든 캐릭터를 붙여서 제대로 움직여보고싶다
어떤 그림이 나올까 기대반 걱정반이다