본문 바로가기

프로그래밍/libGDX

[libGDX] 곡선 함수

곡선 궤적

게임을 만들다 보면 곡선 경로가 필요한 경우가 많습니다. 적이 쏘는 탄환의 궤적이 곡선으로 날아가거나 3D 게임에서 검의 궤적을 표현하고자 할때 유용하게 사용됩니다. 그 외에도 전선의 모양을 보여줄때 곡선은 유용하게 사용할 수 있습니다. 보통 생각나는 곡선은 중학교때 배우는 2차 함수와 같은 곡선이 있지만, 게임 및 여러 소프트웨어에서 사용되는 곡선은 다른 곡선을 많이 사용합니다. 가장 유명한 곡선이라고 하면 베지어 곡선을 생각할 수 있을 것입니다. 베지어 곡선은 가장 보편적으로 사용되는 곡선입니다. 자세한 설명은 나중에 하도록 하겠습니다.


곡선은 전선을 표현할때 사용될 수 있다.


곡선의 조건

곡선의 가장 기본적인 조건은 부드럽게 이어져야 한다는 것입니다. 중간에 끊기는 부분이 있으면 안되고, 꺽이는 부분이 없이 부드러워야합니다.

곡선과 아닌것


곡선의 표현

곡선은 일반적으로 매개변수로 표현됩니다. 가장 쉽게 생각할 수 있는 곡선은 이차곡선으로 y=x^2 으로 표현할 수 있습니다. 하지만 매개변수로 표현되는 곡선은 x, y와 같은 좌표값을 사용하지 않고 벡터와 매개변수 1개로만 표현됩니다. 가령 위의 이차곡선은 

v = v1 * t + v2 * t^2 , v1 = (1, 0), v2 = (0, 1)

으로 표현될 수 있습니다. 여기서 t가 매개변수이고 곡선은 t에 의해 interpolated된다고 말합니다. t는 0 ~ 1의 값을 갖을 수 있습니다. 

쉽게 말하면 어떤 곡선이 있을때 t 값이 0이면 시작점이고 t 값이 1이면 끝점입니다. t가 0 ~ 1이면 곡선상의 한 점을 가르키게 됩니다. 0보다 작으면 시작점보다 연장곡선을 그은 지점이 되고 1보다 크면 끝점에 연장곡선을 그어서 생긴 지점입니다. 그리고 이렇게 곡선이 하나의 float값으로 표현이 될때 그 float 값에 의해 interpolated 된다고 할 수 있습니다. (Interpolated 된다는 것은 곡선 함수에 float 값을 집어 넣으면 어떤 좌표가 튀어 나오는 것으로 생각하면 될 것 같습니다.)


곡선의 Interpolation

거의 모든 곡선들은 매개변수들로 표현되고, 매개변수로 표현하는 것이 공간상에서 다룰때 여러가지 편한점이 많습니다. 계산이 빨리될 수 있고, 미분값을 찾기 쉽고, 어떤 점이 주어졌을때 그 점과 가까운 곡선상의 점을 찾기 쉽습니다. 미분값을 구하기 쉽다는 것은 곡선의 어떤 점에서 속도를 구하기 쉽다는 말입니다. 그래서 여러모로 매개변수로 표현된 곡선을 유용하게 사용됩니다.


Libgdx에서 제공되는 곡선들

Libgdx에서 제공되는 곡선은 3가지가 있습니다. Bezier, BSpline, Catmull Rom Spline 이렇게 3가지 입니다. 3가지 곡선들은 모두 Path 인터페이스를 구현하고 있습니다. Path 인터페이스에서 구현되는 메쏘드는 4가지 입니다. derivativeAt, valueAt, approximate, locate 이렇게 4가지 입니다.

(T는 제너릭 클래스입니다. Vector2나 Vector3와 같은 좌표클래스가 들어올 수 있습니다.)

  • T derivativeAt (T out, float t) : 곡선의 t 지점에서의 접선 벡터를 out에 넣어줍니다.
  • T valueAt (T out, float t) : 곡선의 t 지점의 좌표를 out에 넣어줍니다.
  • float approximate (T v) : 주어진 v 좌표와 가장 가까운 곡선 상의 점을 찾아 float 값으로 돌려줍니다. (Interpolated 값을 돌려줍니다.)
  • float locate (T v) : approximate와 동일한 기능을 수행합니다. 하지만 approximate보다 더욱 정교하게 작동되고 CPU를 더 많이 소모합니다.

여기서 유의해야 할 점은 derivativeAt과 valueAt 메쏘드들은 반환될 벡터를 넣어주어야 한다는 것입니다. 이것은 내부적으로 새로운 벡터 객체가 만들어지는 것을 방지하기 위함입니다. 다시 말하면 메모리 효율성 때문입니다. 그래서 derivativeAt과 valueAt에 첫번째 인자는 찾은 좌표값을 저장하기 위한 벡터를 넣어 주어야 합니다.

Bezier, BSpline, Catmull Rom Spline 에 대한 각각의 자세한 차이점은 다른 글들을 참고해주시면 되겠습니다. 여기서는 간단한 차이만 언급하겠습니다.

Bezier

Bezier 곡선은 2개, 3개, 4개의 점을 받습니다. 점의 갯수에 따라 2차, 3차, 4차 Bezier 곡선이라고 불립니다. Libgdx에서 Bezier의 생성자는 다음과 같이 생겼습니다.

Bezier(T... points)

Bezier(T[] points, int offset, int length)

Beizer(Array<T> points, int offset, int length)

모든 생성자는 Bezier에서 사용될 포인트를 넣는 것입니다. 이 포인트들은 컨트롤 포인트로 사용됩니다. Bezier에 넣어준 point 들에 의해 생기는 곡선은 다음과 같이 생겼습니다. (여기는 대략적으로 그림으로만 보여주겠습니다. 어떻게 그림이 그려지는 자세한 내용은 Bezier 곡선에 대해 전문적으로 다룬 글을 참조해 주세요.)


2차, 3차, 4차 베지어 곡선


BSpline

BSpline의 생성자는 여러개의 포인트를 받습니다.

BSpline(T[] control points, int degree, boolean continuous)

BSpline은 Bezier 곡선의 확장판이라고 볼 수 있습니다. Bezier 곡선이 4차 Bezier까지만 존재하는것에 비해 BSpline은 어떤 갯수의 포인트로도 만들어 질 수 있습니다. 생긴것은 Bezier와 비슷하게 생겼습니다.


Catmull Rom Spline

Catmull Rom Spline의 생성자는 여러개의 포인트를 받습니다. 

CatmullRomSpline(T[] controlPoints, boolean continuous)

하지만 BSpline에서 넣어준 포인트들은 컨트롤 포인트로 사용되는것고 다르게 Catmull Rom Spline은 주어진 점들을 모두 지나가는 곡선이 만들어집니다. 다른 곡선들과 다르게 원하는 점들을 지나는 곡선을 만들 수 있다는 장점이 있습니다.


Catmull Rom Spline


마치면서

이번 포스팅에서는 곡선들에 대해 알아봤습니다. 게임 뿐만 아니라 다른 종류의 어플리케이션을 만들때 곡선은 유용하게 쓰일 수 있습니다. 그래프에디터와 같은 것을 만들때도 곡선은 굉장히 유용합니다. Libgdx에서는 단순히 곡선 함수들만 제공하는 것이 아니라 접선 벡터, 가장 가까운 점을 알 수 있는 메쏘드들도 제공하고 있으니 잘 활용하면 유용하게 사용할 수 있습니다.


곡선으로 날아가는 탄환