3 point Curve equation (bezier curve)
https://www.gpgstudy.com/forum/viewtopic.php?t=9715
두개의 끝점(P0, P2)과 하나의 콘트롤 포인트(P1)을 이용하여 quadratic Bezier spline
곡선을 그리는 매개변수 방정식은 다음과 같습니다.[1] P'(t) = (1-t)^2 * P0 + 2t(1-t)P1 + t^2 * P2 (0<= t <= 1)
그런데 이방정식을 이용하여 그려지는 곡선은 P1을 지나지 않으므로
이 방정식을 이용하여 아래와 같이 특정 t시간에 가운데점을 반드시
지나게하는 P1을 구한후 [1]식을 이용하여 곡선을 그리면 될듯 합니다.
P1 = (P'(t) - (1-t)^2 * P0 - t^2 * P2) / 2t(1-t)
그리고 Bezier spline 곡선은 콘트롤 포인트가 많을수록 다양한 형태의 곡선을 만들수
있으니 점이 많을수록 부드러운 곡선을 그릴수 있다고 말할수도 있겠네요.
먼저 blender()는 점 A와 점 B 그리고 가중치 t를 전달받아 블랜딩한 결괏값을 반환하는 함수다.
function blender(A, B, t) {
if (t === 0) {
return A;
}
if (t === 1) {
return B;
}
return ((1 - t) * A) + (t * B); // or A + t * (B - A)
}
이때 blender()는 좌표 하나에 대한 연산만 책임지므로 x, y 좌표를 연산하기 위해 blend()를 작성한다.
function blend(x1, x2, y1, y2, t) {
const x = blender(x1, x2, t);
const y = blender(y1, y2, t);
return {x, y};
}
다음으로 blend()를 이용해 점 A와 점 B의 좌표를 전달해 점 E의 좌푯값을 구하고 점 B와 점 C의 좌표를 전달해 점 F의 좌표를 구한다. 그리고 다시 점 E와 점 F의 좌표를 전달해 점 P의 좌표를 구하는 방식으로 공식을 구현한다.
interpolateBtn.addEventListener(\'click\', function() {
// Start the interpolation.
raf(function(t) {
const posE = blend(posA.x, posB.x, posA.y, posB.y, t);
const posF = blend(posB.x, posC.x, posB.y, posC.y, t);
const posP = blend(posE.x, posF.x, posE.y, posF.y, t);
...
}, 1000);
});
아래 데모를 실행해 보자. 점 P가 보간되면서 그려진 곡선을 2차 베지에 곡선이라고 한다.
void bezier2( float x0,float y0,float z0, float x1,float y1,float z1, float x2,float y2, float z2, float x3,float y3, float z3 ) { // measure chord lengths float c1,c2,c3; c1=dist( x0,y0,z0, x1,y1,z1 ); c2=dist( x1,y1,z1, x2,y2,z2 ); c3=dist( x2,y2,z2, x3,y3,z3 ); float t1,t2; t1=c1/(c1+c2+c3); t2=(c1+c2)/(c1+c2+c3); float b0,b1,b2,b3; b0 = pow( 1 - t1 , 3 ); b1 = pow( 1 - t2 , 3); b2 = pow( t1 , 3 ); b3 = pow( t2 , 3 ); // make curve segment lengths proportional to chord lengths float a,b,c,d; a = t1 * ( 1 - t1 ) * ( 1 - t1 ) * 3; b = ( 1 - t1 ) * t1 * t1 * 3; c = t2 * ( 1 - t2 ) * ( 1 - t2 ) * 3; d = ( 1 - t2 ) * t2 *t2 *3; float e,f,g,h,i,j; e = x1 - ( x0 * b0 ) - ( x3 * b2 ); f = x2 - ( x0 * b1 ) - ( x3 * b3 ); g = y1 - ( y0 * b0 ) - ( y3 * b2 ); h = y2 - ( y0 * b1 ) - ( y3 * b3 ); i = z1 - ( z0 * b0 ) - ( z3 * b2 ); j = z2 - ( z0 * b1 ) - ( z3 * b3 ); x2 = ( e - a / c * f ) / ( b - a * d / c); x1 = ( e - ( b * x2 ) ) / a; y2 = ( g - a / c * h ) / ( b - a * d / c); y1 = ( g - ( b * y2 ) ) / a; z2 = ( i - a / c * j ) / ( b - a * d / c); z1 = ( i - ( b * z2 ) ) / a; bezier(x0,y0,z0, x1,y1,z1, x2,y2,z2, x3,y3,z3); }
I'm working on a sketch to showcase it.
Let P0, P1, P2 be the control points, and Pc be your fixed point you want the curve to pass through.
Then the Bezier curve is defined by
P(t) = P0*t^2 + P1*2*t*(1-t) + P2*(1-t)^2
...where t goes from zero to 1.
There are an infinite number of answers to your question, since it might pass through your point for any value of t... So just pick one, like t=0.5, and solve for P1:
Pc = P0*.25 + P1*2*.25 + P2*.25
P1 = (Pc - P0*.25 - P2*.25)/.5
= 2*Pc - P0/2 - P2/2
There the "P" values are (x,y) pairs, so just apply the equation once for x and once for y:
x1 = 2*xc - x0/2 - x2/2
y1 = 2*yc - y0/2 - y2/2
...where (xc,yc) is the point you want it to pass through, (x0,y0) is the start point, and (x2,y2) is the end point. This will give you a Bezier that passes through (xc,yc) at t=0.5.
댓글
댓글 쓰기