본문 바로가기

프로그래밍/Unity 3D

[Unity] 유니티 3D Vector의 선형보간 Lerp 정확한 사용법

[Unity] 유니티 3D Vector의 선형보간 Lerp


 오늘은 유니티에서 굉장히 많이 이용되는 선형 보간 함수를 소개하겠습니다,


우선 선형보간이란 이런 것입니다.


선형 보간법

위키백과, 우리 모두의 백과사전.

선형 보간법(線型補間法, linear interpolation)은 끝점의 값이 주어졌을 때 그 사이에 위치한 값을 추정하기 위하여 직선 거리에 따라 선형적으로 계산하는 방법이다.


단순히 이 개념을 이해하고서 유니티에 적용하는것은 쉽지 않을 것입니다. 유니티에서 사용하기 위해 쉬운말로 풀어 쓰면 이렇습니다.


어떤 수치에서 어떤 수치로 값이 변경되는데 한 번에 변경되지 않고 부드럽게 변경되게 하고싶다. 할 때!!


습니다. 이럴 때 선형보간을 사용하시면 됩니다. 제가 주로 사용하는 선형보간 함수들은 이렇습니다.


Mathf.Lerp -> 숫자 간의 선형 보간


Vector2.Lerp -> Vector2 간의 선형 보간


Vector3.Lerp -> Vector3 간의 선형 보간


Quaternion.Lerp -> Quaternion 간의 선형 보간 (회전)


오브젝트를 부드럽게 이동하거나 회전할 시에 사용하곤 합니다. 카메라 추적 스트립트에 사용할 수 있겠습니다.


그럼 어떻게 수치들이 부드럽게 변경되게 할까요? 예제를 통해 알아보겠습니다.


--> 오브젝트 A의 위치가 0,0,0 에 있다고 하겠습니다. 이 오브젝트의 위치를 5,5,5로 바꾸고 싶은데 부드럽게 이동하고 싶습니다.

이 때 void Update() 내에 선형보간 함수를 사용할 수 있습니다. MomoBehavior을 상속 받은 상태여야합니다. (Update를 사용하기 위해서)


        public GameObject A; //new Vector3(0, 0, 0);
        Vector3 pos = new Vector3(5, 5, 5);

        void Awake()
        {
            A.transform.position = Vector3.zero;//new Vector3(0, 0, 0);
        }
        void Update()
        {
            A.transform.position = Vector3.Lerp(A.transform.position, pos, Time.deltaTime);
        }


위와 같이 입력 해 줄 수 있습니다. Time.delaTime에 1이상의 수를 곱하면 그 수가 커질 수록 보이는 속도가 빨라집니다.

이 정도만 알고 있으면 사용하는데에는 우선 문제가 없습니다. 하지만 궁금하신 분들을 위해 Vector3.Lerp 이 선형 보간 함수를 좀 더 구체적으로 설명드리겠습니다.


Vector3.Lerp(위치1, 위치2, 0~1사이의 실수) 라고 하겠습니다.


Vector3.Lerp가 반환하는 Vertor3의 값은 마지막 인자에 따라 바뀝니다.


따라서

Vector3.Lerp(위치1, 위치2, 0) = 위치1

Vector3.Lerp(위치1, 위치2, 1) = 위치2


이러한 벡터 값을 반환하게 됩니다. Vector3.Lerp(위치1, 위치2, 0.5f) = 위치1과 위치2의 중간위치 이겠지요.


Time.deltatime 은 지난 프레임이 완료되는 데 까지 걸린 시간을 나타내며, 단위는 초를 사용합니다. (읽기전용)


당연한 말이지만 이 개념을 제대로 이해해야 Time.deltatime을 이용하기가 수월합니다.


위치1 = Vector3.Lerp(위치1, 위치2, Time.deltatime)


기본적으로 Update 함수는 한프레임에 한번 호출됩니다.

Update 함수에서 인자에 Time.deltatime 을 넣어주게 되면

기존의 위치 1은 위치 2의 방향으로  둘 사이의 거리 * (전 프레임에 걸린시간) 만큼 이동하게 되는 것입니다.

예를 들어 둘사이의 거리가 10이고  전프레임에 걸린시간이 0.1f 초 였다고 가정해 보겠습니다. (=1초에 10프레임 즉 10fps인 경우입니다.)


간단하게 UpdateN = N번째 호출이라고 하겠습니다. 위치1 = 0, 위치2 = 10 이라고 하겠습니다. 방향은 단일 축으로 생각하겠습니다.


Vector3.Lerp(위치1, 위치2, Time.deltatime) 를 Uptate에 입력했을때,

(단일 축이기때문에 숫자만 변경할 시 Mathf.Lerp를 사용해도 무방합니다.)


Update0 -> 위치1 = 0

Update1 -> 위치1 = 1 // 전 프레임의 위치 +(10 * 0.1)

Update2 -> 위치1 = 1.9 // 전 프레임의 위치 +(9 * 0.1)

Update3 -> 위치1 = 2.71 // 전 프레임의 위치 +(8.1 * 0.1)

Update4 -> 위치1 = 3.439  // 전 프레임의 위치 +(7.29 * 0.1)

...

...

Update? -> 위치1 = 위치2


점점 적은 수치만큼 증가하다가 결국 위치1의 오브젝트가 위치2에 위치하게 됩니다. 여기서 Time.deltaTime에 2f를 곱해주게 되면


Vector3.Lerp(위치1, 위치2, Time.deltatime * 2f)


Update0 -> 위치1 = 0

Update1 -> 위치1 = 2 // 전 프레임의 위치 +(10 * 0.2)

Update2 -> 위치1 = 3.8 // 전 프레임의 위치 +(9 * 0.2)

Update3 -> 위치1 = 5.42 // 전 프레임의 위치 +(8.1 * 0.2)

Update4 -> 위치1 = 6.878  // 전 프레임의 위치 +(7.29 * 0.2)

...

...

Update? -> 위치1 = 위치2


정확히 원래의 속도보다 두 배 빨리 이동하는 셈입니다. 결론적으로 Time.deltaTime * Speed 정도로 생각할 수 있습니다.


처음 접하시는 분들은 이해하기가 조금 난해하실 수도 있지만 이해해 두시면 추후에 꼭 도움이 될거라 생각합니다. 감사합니다.