개발/OpenGL / / 2022. 3. 2. 20:32

OpenGL 공부일지 - OpenGL Super Bible 베지어 곡선과 스플라인

반응형

Interpolation, Lines, Curves, and Splines

interpolation은 점들의 중간값을 찾는 작업이다.

점 A, B를 잇는 선이 있을 때 선의 방정식은 위와 같다. P는 선 위의 임의의 점이고, D는 A에서 B로의 벡터이다.

t가 0이면 P는 A이고, 1이면 B가 된다.

t가 변함에 따라 A와 B중 한쪽으로 이동하는것이 선형 보간이다. 

vec4 mix(vec4 A, vec4 B, float t);

GLSL에서는 선형 보간을 위한 mix함수가 있다. 버전에 따라 각각의 인자들이 vector / scalar 를 갖는 여러 버전이 있다.

Curves

곡선은 세 개 이상의 control point가 필요하다. 두 개는 종단점이고, 나머지가 곡선의 모양을 결정한다. 

위 그림에서는 A, B, C의 세 control point를 가지고, A, C는 종단점, B가 모양을 결정하는 점이다.

선AB와 선 BC의 선형보간으로 D와 E를 구하고, 선 DE를 보간하여 P를 구한다. 여기서 보간인자 t를 조정하여 P는 그림의 곡선대로 이동한다.

D와 E를 치환하여 정리하면 다음과 이 도출된다.

이 식을 t에 대한 2차 방정식으로 본다. 2차 베지어 곡선이라고 부른다.

vec4 quadratic_bezier(vec4 A, vec4 B, vec4 C, float t)
{
vec4 D = mix(A, B, t); // D = A + t(B - A)
vec4 E = mix(B, C, t); // E = B + t(C - B)
vec4 P = mix(D, E, t); // P = D + t(E - D)
return P;
}

2차 베지어 곡선은 위와 같은 방식으로 GLSL에서 mix함수를 이용해 구현한다. 위에서 구한 결과를 선형적으로 보간하면 끝이다.

네 번째의 control point를 추가하면 3차 베지어 곡선이 만들어진다.

2차 베지어 곡선과 구성과정은 비슷하다. 선 AB, 선 BC, 선 CD의 각각을 보간하여 점 E,F,G를 구한다.

또 선 EF, 선 FG을 따라 보간하여 점 H,I를 구하고, 이들을 보간하여 P를 구한다. 

2차 베지어 곡선에서 t에 대한 2차 방정식이 전개된 것처럼, 3차 베지어 곡선은 3차 방정식으로 도출된다. 

vec4 cubic_bezier(vec4 A, vec4 B, vec4 C, vec4 D, float t)
{
vec4 E = mix(A, B, t); // E = A + t(B - A)
vec4 F = mix(B, C, t); // F = B + t(C - B)
vec4 G = mix(C, D, t); // G = C + t(D – C)
vec4 H = mix(E, F, t); // H = E + t(F - E)
vec4 I = mix(F, G, t); // I = F + t(G - F)
vec4 P = mix(H, I, t); // P = H + t(I - H)
return P;
}

GLSL의 mix함수로 위 식을 보간하면 위와 같다.

vec4 cubic_bezier(vec4 A, vec4 B, vec4 C, vec4 D, float t)
{
vec4 E = mix(A, B, t); // E = A + t(B - A)
vec4 F = mix(B, C, t); // F = B + t(C - B)
vec4 G = mix(C, D, t); // G = C + t(D - C)
return quadratic_bezier(E, F, G, t);
}

3차 베지어 곡선 공식 구조는 위와 같은 2차 공식을 포함한다. 그러므로 위처럼 control point가 4개인 경우를 계산 후 control point가 3개인 계산은 2차 베지어 곡선 함수를 이용하여 return할 수 있다.

vec4 quintic_bezier(vec4 A, vec4 B, vec4 C, vec4 D, vec4 E, float t)
{
vec4 F = mix(A, B, t); // F = A + t(B - A)
vec4 G = mix(B, C, t); // G = B + t(C - B)
vec4 H = mix(C, D, t); // H = C + t(D - C)
vec4 I = mix(D, E, t); // I = D + t(E - D)
return cubic_bezier(F, G, H, I, t);
}

위와 같은 방식으로 더 고차원인 5차 배지어 곡선도 구현할 수 있다. 이러한 방식을 layering이라고 한다. 

하지만 보통은 4개의 control point가 넘어가면 스플라인이 사용되는 경우가 많다.

Splines

spline은 Bezier와 같이 여러 작은 곡선으로 이루어진 긴 곡선이다. 곡선의 끝을 나타내는 control point는 segment간에 공유된다. 내부의 control point는 인접한 segment간 공유되거나 연결된다.

위 그림의 스플라인은 각각 3차 베지어 곡선으로 이루어져있다. A,B,C,D로 이루어진 베지어곡선이 D로 다음 베지어 곡선과 연결되는 방식이다.

이러한 스플라인은 3차 베지어 곡선들로 이루어져있어 3차 베지어 스플라인이라고 한다. 3차 B-스플라인이라고도 한다.

스플라인을 따라 보간하는 t값은 0.0에서 3.0사이를 각 세 개의 영역(0~1, 1~2, 2~3)으로 나누어 구간별로 각 베지어 곡선을 따라 보간한다.

t의 정수부분이 보간할 곡선의 segment를 결정하고, 소수 부분은 각 segment에서 얼마나의 위치까지 보간하는지를 결정한다.

t가 0.0~1.0 사이의 값인 경우, 곡선의 구간 번호를 곱하여 제어점의 개수와 상관없이 원하는 영역 값을 사용하는 방법도 있다.

vec4 cubic_bspline_10(vec4 CP[10], float t)
{
    float f = t * 3.0;
    int i = int(floor(f));
    float s = fract(t);
    if (t <= 0.0)
    return CP[0];
    if (t >= 1.0)
    return CP[9];
    vec4 A = CP[i * 3];
    vec4 B = CP[i * 3 + 1];
    vec4 C = CP[i * 3 + 2];
    vec4 D = CP[i * 3 + 3];
    return cubic_bezier(A, B, C, D, s);
}

위 코드는 CP 열 개의 점을 이용하여 3차 베지어 스플라인을 따라 보간한다. segment는 3개이다.

스플라인의 부드러운 움직임을 위해서는 control point의 위치에 유의해야하는데, t에 대한 곡선의 미분 방정식이 연속적이도록 해야한다. 불연속적이라면 급작히 방향을 바꾸거나 튀는 움직임이 보인다. t의 2차 미분 방정식은 P점의 속도 변화율(가속도)이다.

연속적인 1차 미분을 가지면 C^1연속적, 2차 미분을 가지면 C^2연속적이라고 한다. 베지어 곡선구간은 모두 연속적이지만, 스플라인의 경우 그렇지 않은 상황이 발생할 수 있다. 스플라인의 연속성에 주의해야한다.

 

위의 스플라인 그림을 보자. D 연결점에 대해서 점C, E가 직선을 이루고 D가 중앙에 위치한다.

V_D가 D에서의 E쪽으로의 구간에서 속도이다. C와 E는 위처럼 표현된다. 

마찬가지로 V_A는 A에서 B쪽으로의 구간에서 속도이다. 

 

3차 B-스플라인의 연결점에서 위치가 속도가 주어지면 다른제어점도 실시간으로 계산할 수 있다. 이를 3차 에르미트 스플라인 또는 cspline이라고 한다. 부르럽고 자연스러운 애니메이션을 위해 사용된다.

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유