Life Archive

INTRO

Unity3D를 학습하다보면 이동(Translate)과 회전(Rotation)을 배우게 되는데, 이 때 보간법(Interpolation)을 배우게 된다.

원하는 시작 지점과 끝 지점 사이에 원하는 함수를 사용하여 함숫값이나 근삿값을 구하는 방법이다.

 

가장 기초적으로 배우는 보간법은 바로 선형 보간법(Linear Interpolation), Lerp이다.

말 그대로 선형, 직선 함수를 사용하여 두 지점 사이에 함숫값을 구하는 보간법인데,

실제로 유니티에서 구현하다보면 선형으로 변하는게 아닌 곡선으로 값이 나올 때가 있다.

 

의도적으로 그런 효과를 원한다면 괜찮겠지만,

선형(직선) 보간법을 사용한만큼 선형적으로 변해야만 정확하게 사용한 것이다.

 

언제 그렇고, 어떻게 코드를 작성하면 그런지, 그리고 이 때는 어떤 방법으로 해결해야하는 지 알아보았다.

 


CONTENT

Lerp를 사용하여 값을 출력하는 가장 기본적인 코드는 아래와 같다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FollowCam : MonoBehaviour {

	private Transform camTr;
    
    // 반응 속도
    public float damping = 10.0f;
    
	void Start()
    	{
        	// 시작 지점
        	camTr = this.gameObject.GetComponent<Transform>();
    	}
     
    void LateUpdate() 
    	{
        	// 도착 지점
        	Vector3 pos = targetTr.position
                      + (-targetTr.forward * distance)
                      + (Vector3.up * height);
            
            // Lerp
        	camTr.position = Vector3.Lerp(camTr.position, pos, Time.deltaTime * damping);
		}
}

이렇게 작성하고 유니티에서 실행시키면 선형적으로 변하는게 아닌,

점차 빨라졌다가 도착지점에 가까워지면 느려지는 곡선으로 변하게 된다. 

즉, 개발자가 의도하고자 하는 선형적인 변화가 아닌 것이다.

 

왜 이렇게 되는 지 확인해보자면,Lerp의 Parameter에 주목하면 된다.

① 시작 지점 : 위 코드에서 시작 지점은 camTr.position이다. camTr은 LateUpdate 내에서 매 프레임마다 변하는 값이다.

② 끝 지점 : 끝 지점도 마찬가지로 targetTr을 조금 수정한 값으로 매 프레임마다 변하는 값이다.

③ 보간값 : Time.deltaTime(보통 약 0.02f) 값에 고정값 damping을 곱하므로 사실 고정된 값이다.

 

정리하자면, 시작 지점과 끝 지점은 매 프레임마다 변하지만 보간값은 고정된 값이다.

 

매 프레임마다 반복하며 Object가 도착 지점에 가까워질수록 고정된 값(약 0.2f)로 이동하며

총 거리가 짧아지는 것에 따라 이동 거리도 짧아질 수밖에 없다.

그래서 시작할 때와 도착할 때 속도가 선형적으로 변하는게 아닌 것이다.

 

그렇다면, 어떻게 해야 선형적으로, Lerp를 정확하게 사용할 수 있을까?

그건 바로 변하는 값과 고정된 값을 바꿔주면 된다.

즉, 시작 지점과 끝 지점을 고정하고 보간값을 변하는 값으로 바꿔주면 된다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FollowCam : MonoBehaviour {

    public Transform startPosition;
    public Transform endPosition;

    float lerpTime = 0.5f;
    float currentTime = 0;
    
	void Start()
    	{
        	// 시작 지점
        	camTr = this.gameObject.GetComponent<Transform>();
    	}
     
    void LateUpdate() 
    	{
        	// ※ 보간법 사용 시 주의점
        	// Lerp, Slerp 등 보간 함수에 인자를 넣을 때, 시작 좌표가 매번 달라지고 보간값이 고정이라면 선형적으로 보간되지 않는다. (처음에 빠르게 올라오다가 나중에 느려진다.)
        	// ① Start와 End를 좌표를 유니티에서 Object로 만들어 사용한다.
        	// ② 보간값을 시간에 따라서 변하도록 설정한다.
        	currentTime += Time.deltaTime;

        	if (currentTime >= lerpTime)
        	{
            	currentTime = lerpTime;
        	}
            
            camTr.position = Vector3.Lerp(startPosition.position, endPosition.position, currentTime / lerpTime);
        	// 이렇게 하면 우리가 원하는 선형적으로 보간하여 변하도록 설정할 수 있다.
		}
}

위 코드에서 주목할 것은 currentTime / lerpTime이다.

선형, 즉 직선의 방정식 형태가 들어갔기에 선형적으로 변하게 되는 것이다. 

 

이를 응용하여, 보간값 인자 자리에 직선 형태가 아닌 원하는 곡선 형태의 식을 넣게 된다면,

원하는 보간법을 적절하게 사용할 수 있다.

 


RESULT

예시로 작성한 코드는, 플레이어를 따라가는 카메라에 적용한 스크립트이다.

사실 카메라에 사용하는 보간법은 프레임 보정을 위해 Lerp보다 SmoothDamp를 사용하지만,

UI 이동이나 카메라 말고도 선형 보간법을 사용할 때가 있다면 이런 점을 주의해서 개발하도록 해야한다.


참고자료 :

① https://chicounity3d.wordpress.com/2014/05/23/how-to-lerp-like-a-pro/

 https://www.youtube.com/watch?v=_QOvSLCXm7A&list=PLJ0Lh6SYi2KtblYTCyx5eWXBvIbNqidK0&index=7&t=260s