基本概念
本段内容节选自 怎么理解贝塞尔曲线? – FrancisZhao的回答 – 知乎
贝塞尔曲线于 1962 年,由法国工程师皮埃尔·贝济埃(Pierre Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计,贝塞尔曲线最初由保尔·德·卡斯特里奥于1959年运用德卡斯特里奥算法开发,以稳定数值的方法求出贝塞尔曲线.
贝塞尔曲线有着很多特殊的性质, 在图形设计和路径规划中应用都非常广泛, 我就是想在路径规划中贝塞尔曲线完全由其控制点决定其形状, n个控制点对应着n-1阶的贝塞尔曲线,并且可以通过递归的方式来绘制.
一阶曲线
一阶曲线是一条直线。
$ B_1(t)=P_0+(P_1-P_0)t $
$ B_1(t)=(1-t)P_0+tP_1,t ,t\in[0,1] $
一阶曲线就是很好理解, 就是根据$t$来的线性插值. $P_0$表示的是一个向量$[x,y]$, 其中$x$和$y$是分别按照这个公式来计算的.
二阶曲线
二阶曲线共三个控制点。
在平面内任选 3 个不共线的点,依次用线段连接。在第一条线段上任选一个点 D。计算该点到线段起点的距离 AD,与该线段总长 AB 的比例。
根据上一步得到的比例,从第二条线段上找出对应的点 E,使得 AD:AB = BE:BC。
这时候DE又是一条直线了, 就可以按照一阶的贝塞尔方程来进行线性插值了, t= AD:AE
这时候就可以推出公式了.
$P_0’=(1-t)P_0+tP_1$
对应着上图绿色线段的左端点
$P_1’=(1-t)P_1+tP_2$
对应着上图绿色线段的右端点
$B_2(t)=(1-t)P_0’+tP_1’$
$=(1-t)((1-t)P_0+tP_1)+t((1-t)P_1+tP_2)$
$=(1-t)^2P_0+2t(1-t)P_1+t^2P_2$
对应着绿色线段的一阶贝塞尔曲线(线性插值)
$B_2(t)=(1-t)^2P_0+2t(1-t)P_1+t^2P_2, t\in[0,1]$
整理一下公式, 得到二阶贝塞尔公式.
三次曲线
二阶的贝塞尔通过在控制点之间再采点的方式实现降阶, 每一次选点都是一次的降阶.
四个点对应是三次的贝塞尔曲线. 分别在 AB BC CD 之间采EFG点, EFG三个点对应着二阶贝塞尔, 在EF FG之间采集HI点来降阶为一阶贝塞尔曲线.
Aegisub中的贝塞尔
Aegisub中的贝塞尔曲线用四个控制点,生成一条三阶贝塞尔曲线。
用粒子生成贝塞尔曲线
可以用多个粒子来“合成”一条贝塞尔曲线。
获取一帧的时间
Comment: 0,0:00:00.00,0:00:00.00,Default,Get Frame Dur,0,0,0,code once,msa = _G.aegisub.ms_from_frame(1) msb = _G.aegisub.ms_from_frame(100) if msa == nil and msb == nil then frame_dur = 33 else frame_dur = (msb-msa)/100 end
Bezier_move函数
Comment: 0,0:00:00.00,0:00:00.00,Default,Beizer Curve Move,0,0,0,code once all,function bezier_move(x1,y1,x2,y2,x3,y3,x4,y4,t1,t2,accel,afterimage_blur,afterimage_dur,density) if density == 0 or density == nil then density = 1 end if afterimage_blur == 0 or afterimage_blur == nil then x_blur = 0 y_blur = 0 else x_blur = math.random(-afterimage_blur,afterimage_blur) y_blur = math.random(-afterimage_blur,afterimage_blur) end if afterimage_dur == nil or afterimage_dur < frame_dur then afterimage_dur = frame_dur end if accel == nil then accel = 1 end x_pos = {} y_pos = {} dur = t2 - t1 frames = math.floor(dur/(frame_dur/density)) x_pos[j] = (1-(j/frames)^accel)^3 * x1 + 3*(1-(j/frames)^accel)^2 * ((j/frames)^accel) * x2 + 3*(1-(j/frames)^accel) * ((j/frames)^accel)^2 * x3 + ((j/frames)^accel)^3 * x4 y_pos[j] = (1-(j/frames)^accel)^3 * y1 + 3*(1-(j/frames)^accel)^2 * ((j/frames)^accel) * y2 + 3*(1-(j/frames)^accel) * ((j/frames)^accel)^2 * y3 + ((j/frames)^accel)^3 * y4 if j == 1 then maxloop(frames) end retime("presyl",t1+(j-1)*(frame_dur/density),t1+j*(frame_dur/density)+afterimage_dur) return string.format("\\move(%d,%d,%d,%d)",x_pos[j],y_pos[j],x_pos[j] + x_blur ,y_pos[j] + y_blur) end
function bezier_move(x1,y1,x2,y2,x3,y3,x4,y4,t1,t2,accel,afterimage_blur,afterimage_dur,density)
if density == 0 or density == nil
then density = 1
end
if afterimage_blur == 0 or afterimage_blur == nil then
x_blur = 0
y_blur = 0
else
x_blur = math.random(-afterimage_blur,afterimage_blur) y_blur = math.random(-afterimage_blur,afterimage_blur)
end
if afterimage_dur == nil or afterimage_dur < frame_dur then
afterimage_dur = frame_dur
end
if accel == nil then
accel = 1
end
x_pos = {}
y_pos = {}
dur = t2 - t1
frames = math.floor(dur/(frame_dur/density))
x_pos[j] = (1-(j/frames)^accel)^3 * x1 + 3*(1-(j/frames)^accel)^2 * ((j/frames)^accel) * x2 + 3*(1-(j/frames)^accel) * ((j/frames)^accel)^2 * x3 + ((j/frames)^accel)^3 * x4 y_pos[j] = (1-(j/frames)^accel)^3 * y1 + 3*(1-(j/frames)^accel)^2 * ((j/frames)^accel) * y2 + 3*(1-(j/frames)^accel) * ((j/frames)^accel)^2 * y3 + ((j/frames)^accel)^3 * y4
if j == 1 then
maxloop(frames)
end
retime("presyl",t1+(j-1)*(frame_dur/density),t1+j*(frame_dur/density)+afterimage_dur)
return string.format("\\move(%d,%d,%d,%d)",x_pos[j],y_pos[j],x_pos[j] + x_blur ,y_pos[j] + y_blur)
end
传入值分别为:四个控制点;
t1
提前第一个粒子的开始、结束时间,必须填负数或0;
t2
延后最后一个粒子的开始、结束时间,必须填正数或0;
(t1
和t2
决定了整个曲线的持续时间)
accel
为加速度;
afterimage_blur
为这一个粒子的位移参数;(随机向外扩散)
afterimage_dur
决定单个粒子的持续时间;
density
为总的粒子密度、浓度。
在frames=math.floor(dur/(frame_dur/density))
一句中,density
作为自己设定的变量,决定了frames
的值,而由maxloop(frames)
可知循环次数为frmaes
次,所以density
越大,frames
越大,粒子看起来越密集。[1]
生成一个半圆
Comment: 0,0:00:00.00,0:00:00.00,Default,,0,0,0,template notext noblank,{\an5\bord0!bezier_move($center-$width*1.3/2,$middle,$center-$width*1.3/2,$middle-$width*1.3/2*1.414,$center+$width*1.3/2,$middle-$width*1.3/2*1.414,$center+$width*1.3/2,$middle,-500,0,1,10,2000,7)!\p1\c&H11ECA2&}m 0 0 l 2 0 l 2 2 l 0 2
樱花飘落
樱花绘图代码:[2]
m 9 23 b 8 22 7 21 6 20 b 4 18 3 16 2 12 b 2 9 3 5 4 3 b 5 2 6 1 7 1 b 8 3 8 4 9 5 b 10 4 10 3 11 1 b 15 5 16 8 16 12 b 15 15 14 18 12 20 b 11 21 10 22 9 9 b 8 22 7 21 5 19 b 4 18 2 16 1 11 b 1 8 2 5 4 3 b 5 2 6 1 7 1 b 8 3 8 4 9 5 b 10 4 10 3 11 1 b 13 2 14 3 14 3 b 16 5 17 8 17 11 b 16 16 14 18 13 19 b 11 21 10 22 9 23
Comment: 0,0:00:00.00,0:00:00.00,Default,Get Frame Dur,0,0,0,code once,msa = _G.aegisub.ms_from_frame(1) msb = _G.aegisub.ms_from_frame(100) if msa == nil and msb == nil then frame_dur = 33 else frame_dur = (msb-msa)/100 end
Comment: 0,0:00:00.00,0:00:00.00,Default,Beizer Curve Move,0,0,0,code once all,function bezier_move(x1,y1,x2,y2,x3,y3,x4,y4,t1,t2,accel,afterimage_blur,afterimage_dur,density) if density == 0 or density == nil then density = 1 end if afterimage_blur == 0 or afterimage_blur == nil then x_blur = 0 y_blur = 0 else x_blur = math.random(-afterimage_blur,afterimage_blur) y_blur = math.random(-afterimage_blur,afterimage_blur) end if afterimage_dur == nil or afterimage_dur < frame_dur then afterimage_dur = frame_dur end if accel == nil then accel = 1 end x_pos = {} y_pos = {} dur = t2 - t1 frames = math.floor(dur/(frame_dur/density)) x_pos[j] = (1-(j/frames)^accel)^3 * x1 + 3*(1-(j/frames)^accel)^2 * ((j/frames)^accel) * x2 + 3*(1-(j/frames)^accel) * ((j/frames)^accel)^2 * x3 + ((j/frames)^accel)^3 * x4 y_pos[j] = (1-(j/frames)^accel)^3 * y1 + 3*(1-(j/frames)^accel)^2 * ((j/frames)^accel) * y2 + 3*(1-(j/frames)^accel) * ((j/frames)^accel)^2 * y3 + ((j/frames)^accel)^3 * y4 if j == 1 then maxloop(frames) end retime("presyl",t1+(j-1)*(frame_dur/density),t1+j*(frame_dur/density)+afterimage_dur) return string.format("\\move(%d,%d,%d,%d)",x_pos[j],y_pos[j],x_pos[j] + x_blur ,y_pos[j] + y_blur) end
Comment: 0,0:00:00.00,0:00:00.00,Default,Beizer Curve Move,0,0,0,code once,shape="m 9 23 b 8 22 7 21 6 20 b 4 18 3 16 2 12 b 2 9 3 5 4 3 b 5 2 6 1 7 1 b 8 3 8 4 9 5 b 10 4 10 3 11 1 b 13 2 14 3 b 15 5 16 8 16 12 b 15 15 14 18 12 20 b 11 21 10 22 9 9 b 8 22 7 21 5 19 b 4 18 2 16 1 11 b 1 8 2 5 4 3 b 5 2 6 1 7 1 b 8 3 8 4 9 5 b 10 4 10 3 11 1 b 13 2 14 3 14 3 b 16 5 17 8 17 11 b 16 16 14 18 13 19 b 11 21 10 22 9 23"
Comment: 0,0:00:00.00,0:00:00.00,Default,,0,0,0,template notext noblank,{\an5\bord0!bezier_move(math.random($center-60,$center+60),$top,math.random($center-60,$center+60),math.random($top-15,$top+75),math.random($center-60,$center+60),math.random($top-15,$top+75),math.random($center-60,$center+60),math.random($top-15,$top+75),0,500,1,10,2000,1)!\t(0.8,\frx!math.random(-540,540)!\fry!math.random(-540,540)!\frz!math.random(-540,540)!)\p2\c!math.random(1,2)==1 and "&HF486FF&" or "&HF8C7FD&"!}!shape!
Comment: 0,0:00:00.00,0:00:00.00,Default,,0,0,0,template noblank,{\an5\pos($center,$middle)}
Comment: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,karaoke,{\k63}这{\k63}是{\k63}一{\k63}句{\k63}测{\k63}试{\k63}字{\k63}幕
可以把function中的
y_blur = math.random(-afterimage_blur,afterimage_blur)
改为y_blur = math.random(-afterimage_blur,afterimage_blur*2)
,使y方向上偏移更多
N次贝塞尔粒子曲线
可以调整原先的Bezier函数,使其支持N个控制点。
数学原理
高阶的贝塞尔可以通过不停的递归直到一阶;
仔细看可以发现, 贝塞尔的参数B是二项式(t+(1-t))^n = (1)^n的展开公式.
代码code行[3]
存储单帧时间
msa = _G.aegisub.ms_from_frame(1)
msb = _G.aegisub.ms_from_frame(100)
if msa == nil and msb == nil then
frame_dur = 33
else
frame_dur = (msb-msa)/100
end
存储临时数据
temp = {}
function set_temp(ref,val)
temp[4]= val;
return val;
end
定义n次贝赛尔曲线
function Bezier(n,x,y,t)
p_x = 0 p_y = 0
for i = 1, n, 1 do
p_y = p_y + y[i] * set_temp("bern",bernstein(i-1,n-1,t)) p_x = p_x + x[i] * temp.bern
end
return p_x, p_y
end
这是定义n次贝赛尔曲线的函数,它是为了进一步定义一个个粒子都在该曲线上
伯恩施坦(Bernstein)多项式
function bernstein(i,n,t)
return (factk(n) / (factk(i)*factk(n-i))) * (t^i) * ((1-t)^(n-i))
end
此函数定义了三个参数,最后返回的是几个阶乘和三个参数的计算结果。
阶乘
function factk(n)
k = 1
if (n>1) then
for i = 2, n, 1 do
k = k * i
end
end
return k
end
贝塞尔曲线
function Bezier_Move(s_time,e_time,aftimg_dur,x_blur,y_blur,accel,max_space,...)
a = {...}
if j == 1 then
t1 = s_time
t2 = e_time
dur = t2-t1
n = #a/2
for i = 1,n*2-1,2 do
x[(i+1)/2] = a[i]
end
for i = 2, n*2,2 do
y[i/2] = a[i]
end
c_t = 0
maxloop(2)
f_t = 1/(dur/frame_dur)
end
afterimage_dur = aftimg_dur
if (afterimage_dur<0 ) then
afterimage_dur = 0
end
pos_x, pos_y = Bezier(n,x,y,c_t)
n_t = c_t + f_t
n_x, n_y = Bezier(n,x,y,n_t)
dist = math.sqrt(math.abs(n_x-pos_x)^2+math.abs(n_y-pos_y)^2)
a_t =f_t*(max_space/dist)
if (a_t>f_t) then
a_t = f_t
end
n_t = c_t + a_t
if (n_t < 1) then
maxj = j + 1
end
retime("presyl",t1+dur*(c_t^accel),t1+dur*(n_t^accel)+afterimage_dur)
t = c_t
c_t = n_t
return string.format("\\move(%f,%f,%f,%f,%f,%f)",pos_x,pos_y,pos_x+x_blur,pos_y+y_blur,0,dur-dur*t+afterimage_dur)
end; -- 此行可以改成%.2,即保留两位小数
x = {}
y = {}
Bezier_Move(s_time,e_time,aftimg_dur,x_blur,y_blur,accel,max_space,...)
s_time
决定第一个粒子的开始、结束时间(其他粒子也会相应地变化)
e_time
决定第一个粒子的开始、结束时间(其他粒子也会相应地变化)
s_time
和e_time
不限正负,但要求e_time
–s_time
>0
max_space
是生成两个粒子之间的最大距离,和密度成反比
...
表示n个控制点的坐标
实际应用效果
此函数对整句话生效;如果有音节分隔,则需要使用Firstsyl
Comment: 0,0:00:00.00,0:00:00.00,Default,Get Frame Dur,0,0,0,code once,msa = _G.aegisub.ms_from_frame(1) msb = _G.aegisub.ms_from_frame(100) if msa == nil and msb == nil then frame_dur = 33 else frame_dur = (msb-msa)/100 end
Comment: 0,0:00:00.00,0:00:00.00,Default,set_temp,0,0,0,code,function set_temp(ref,val) temp[4] = val; return val; end temp = {}
Comment: 0,0:00:00.00,0:00:00.00,Default,Bezier(n;x;y;t) ,0,0,0,code once,function Bezier(n,x,y,t) p_x = 0 p_y = 0 for i = 1, n, 1 do p_y = p_y + y[i] * set_temp("bern",bernstein(i-1,n-1,t)) p_x = p_x + x[i] * temp.bern end return p_x, p_y end
Comment: 0,0:00:00.00,0:00:00.00,Default,bernstein,0,0,0,code,function bernstein(i,n,t) return (factk(n) / (factk(i)*factk(n-i))) * (t^i) * ((1-t)^(n-i)) end
Comment: 0,0:00:00.00,0:00:00.00,Default,factk,0,0,0,code,function factk(n) k = 1 if (n > 1) then for i = 2, n, 1 do k = k * i end end return k end
Comment: 0,0:00:00.00,0:00:00.00,Default,Beizer_N,0,0,0,code once,function Bezier_Move(s_time,e_time,aftimg_dur,x_blur,y_blur,accel,max_space,...) a = {...} if j == 1 then t1 = s_time t2 = e_time dur = t2-t1 n = #a/2 for i = 1,n*2-1,2 do x[(i+1)/2] = a[i] end for i = 2, n*2,2 do y[i/2] = a[i] end c_t = 0 maxloop(2) f_t = 1/(dur/frame_dur) end afterimage_dur = aftimg_dur if (afterimage_dur < 0 ) then afterimage_dur = 0 end pos_x, pos_y = Bezier(n,x,y,c_t) n_t = c_t + f_t n_x, n_y = Bezier(n,x,y,n_t) dist = math.sqrt(math.abs(n_x-pos_x)^2+math.abs(n_y-pos_y)^2) a_t =f_t*(max_space/dist) if (a_t > f_t) then a_t = f_t end n_t = c_t + a_t if (n_t < 1) then maxj = j + 1 end retime("presyl",t1+dur*(c_t^accel),t1+dur*(n_t^accel)+afterimage_dur) t = c_t c_t = n_t return string.format("\\move(%f,%f,%f,%f,%f,%f)",pos_x,pos_y,pos_x+x_blur,pos_y+y_blur,0,dur-dur*t+afterimage_dur) end; x = {} y = {}
Comment: 0,0:00:00.00,0:00:00.00,Default,,0,0,0,template line notext,{!Bezier_Move(0,1000,2000,math.random(0,0),math.random(0,0),1,1,$left-40,$top,$left+20,$top-50,$left+40,$top+60,$left+60,$top-70,$left+80,$top+280,$left+100,$top-90,$left+120,$top+100,$left+140,$top-500,$left+160,$top+140,$left+180,$top-300,$left+200,$top+100,$left+240,$top)!\bord0\p4}m 19 4 b 23 8 23 15 19 19 b 15 23 8 23 4 19 b 0 15 0 8 4 4 b 8 0 15 19 4 b 8 0 15 0 19 4
Comment: 0,0:00:00.00,0:00:00.00,Default,,0,0,0,template noblank,{\an5\pos($center,$middle)}
Comment: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,karaoke,测试字幕
描边函数Vector_Move
code行
Vector_Move
function Vector_Move(s_time,e_time,afterimage_dur,x_blur,y_blur,accel,base_pos_x,base_pos_y,max_space,scale_x,scale_y,s,x_add)
if (j == 1) then
t = 0
pos_x = {}
pos_y = {}
if (afterimage_dur < 0 ) then
afterimage_dur = 0
end
c_point_x = {}
c_point_y = {}
point = {}
i = 1
s:gsub("(%S+)", function(w)
point[i] = w i = i + 1
end
)
dur = e_time-s_time
i = 1
m = 0
max_x = -10000
min_x = 10000
max_y = -10000
min_y = 10000
scale_x = scale_x / 100
scale_y = scale_y / 100
while i <= #point do
c_point_x = {}
c_point_y = {}
if point[i] == "m" then
s_point_x = point[i+1]
s_point_y = point[i+2]
i = i + 3
elseif point[i] == "b" then
c_point_x[1] = s_point_x*scale_x
c_point_y[1] = s_point_y*scale_y
for k = 2, 4, 1 do
c_point_x[k] = point[i+1+(k-2)*2]*scale_x
c_point_y[k] = point[i+2+(k-2)*2]*scale_y
end
max_x = math.max(max_x,_G.unpack(c_point_x))
max_y = math.max(max_y,_G.unpack(c_point_y))
min_x = math.min(min_x,_G.unpack(c_point_x))
min_y = math.min(min_y,_G.unpack(c_point_y))
c_point_x[1] = s_point_x*scale_x+base_pos_x
c_point_y[1] = s_point_y*scale_y+base_pos_y
for k = 2, 4, 1 do
c_point_x[k] = point[i+1+(k-2)*2]*scale_x+base_pos_x
c_point_y[k] = point[i+2+(k-2)*2]*scale_y+base_pos_y
end
s_point_x = point[i+5]
s_point_y = point[i+6]
i = i + 7
elseif point[i] == "l" then
c_point_x[1] = s_point_x*scale_x
c_point_y[1] = s_point_y*scale_y
c_point_x[2] = point[i+1]*scale_x
c_point_y[2] = point[i+2]*scale_y
max_x = math.max(max_x,_G.unpack(c_point_x))
max_y = math.max(max_y,_G.unpack(c_point_y))
min_x = math.min(min_x,_G.unpack(c_point_x))
min_y = math.min(min_y,_G.unpack(c_point_y))
c_point_x[1] = s_point_x*scale_x+base_pos_x
c_point_y[1] = s_point_y*scale_y+base_pos_y
c_point_x[2] = point[i+1]*scale_x+base_pos_x
c_point_y[2] = point[i+2]*scale_y+base_pos_y
s_point_x = point[i+1]
s_point_y = point[i+2] i = i + 3
else
_G.aegisub.debug.out("Unknown drawing command. You can use only \"m\" , \"b\" , \"l\"^^;")
i = #point+1
end
c_t = 0
n = #c_point_x
if n ~= 0 then
while c_t <= 1 do
m = m + 1
pos_x[m],
pos_y[m] = Bezier(n,c_point_x,c_point_y,c_t)
n_x, n_y = Bezier(n,c_point_x,c_point_y,c_t+0.1)
dist = math.sqrt(math.abs(n_x-pos_x[m])^2+math.abs(n_y-pos_y[m])^2)
c_t = c_t + max_space/dist*0.1
end
end
end
maxloop(m)
end
retime("presyl",s_time+dur*(t^accel),s_time+dur*((t+1/m)^accel)+afterimage_dur)
t = t + 1/m
adjust_x = -(max_x - min_x) / 2 - min_x
adjust_y = -(max_y - min_y) / 2 - min_y
return
string.format("\\move(%f,%f,%f,%f,%f,%f)",pos_x[j]+x_add,pos_y[j],pos_x[j]+x_blur+x_add,pos_y[j]+y_blur,afterimage_dur/2,afterimage_dur)
end
s_time
决定第一个粒子的开始时间、结束时间(其他离子也会相应的变化)
e_time
决定最后一个粒子的开始时间、结束时间(其他离子也会相应的变化)
e_time
–s_time
>0
举例:
s=500,e=0,则第一个粒子开始时间就延后500ms,最后一个粒子不变,剩下的其他粒子平分这中间的时间。由于每个粒子位置不一样,此时的移动效果看起来是反向的
s=0,e=500,反之是正向的
s=-500,e=-2000,与第一个同理,是反向的
s=0,e=0,粒子不动,静态。
afterimage_dur
是单个粒子的持续时间
x_blur
和y_blur
是x、y方向的随机移动
accel
加速度参数
base_pos_x
和base_pos_y
这两个参数将原始绘图的(0,0)
点定位在(base_pos_x+x_add,bas_pos_y)
所以这两个参数决定了粒子描边移动的起点
max_space
决定生成的两个相邻粒子间的最大距离,与密度成反比
scale_x
和scale_y
是对原始矢量绘图的缩放比例(基准100)
s
是要描边的矢量绘图(字符串)
x_add
表示在base_pos_x
设定的粒子x坐标上,再在x坐标上加x_add
,即在base_pos_x
的基础上,粒子在x方向上平移
x_add
一般填0,但如果要描移动图形的边,就要用x_add
,且此时x_add
是个变化的值,例如(j-1)/maxj*$lwidth
描边的绘图最好用圆形粒子,而不是方块
辅助函数和N次贝塞尔粒子曲线一致。
实际应用
Comment: 0,0:00:00.00,0:00:00.00,Default,Get Frame Dur,0,0,0,code once,msa = _G.aegisub.ms_from_frame(1) msb = _G.aegisub.ms_from_frame(100) if msa == nil and msb == nil then frame_dur = 33 else frame_dur = (msb-msa)/100 end
Comment: 0,0:00:00.00,0:00:00.00,Default,temp func,0,0,0,code once,temp = {} function set_temp(ref,val) temp[4] = val return val end
Comment: 0,0:00:00.00,0:00:00.00,Default,Bezier(n;x;y;t),0,0,0,code once,function Bezier(n,x,y,t) p_x = 0 p_y = 0 for i = 1, n, 1 do p_y = p_y + y[i] * set_temp("bern",bernstein(i-1,n-1,t)) p_x = p_x + x[i] * temp.bern end return p_x, p_y end
Comment: 0,0:00:00.00,0:00:00.00,Default,bernstein,0,0,0,code,function bernstein(i,n,t) return (factk(n) / (factk(i)*factk(n-i))) * (t^i) * ((1-t)^(n-i)) end
Comment: 0,0:00:00.00,0:00:00.00,Default,factk,0,0,0,code,function factk(n) k = 1 if (n > 1) then for i = 2, n, 1 do k = k * i end end return k end
Comment: 0,0:00:00.00,0:00:00.00,Default,Vector Move Function,0,0,0,code once,function Vector_Move(s_time,e_time,afterimage_dur,x_blur,y_blur,accel,base_pos_x,base_pos_y,max_space,scale_x,scale_y,s,x_add) if (j == 1) then t = 0 pos_x = {} pos_y = {} if (afterimage_dur < 0 ) then afterimage_dur = 0 end c_point_x = {} c_point_y = {} point = {} i = 1 s:gsub("(%S+)", function(w) point[i] = w i = i + 1 end) dur = e_time-s_time i = 1 m = 0 max_x = -10000 min_x = 10000 max_y = -10000 min_y = 10000 scale_x = scale_x / 100 scale_y = scale_y / 100 while i <= #point do c_point_x = {} c_point_y = {} if point[i] == "m" then s_point_x = point[i+1] s_point_y = point[i+2] i = i + 3 elseif point[i] == "b" then c_point_x[1] = s_point_x*scale_x c_point_y[1] = s_point_y*scale_y for k = 2, 4, 1 do c_point_x[k] = point[i+1+(k-2)*2]*scale_x c_point_y[k] = point[i+2+(k-2)*2]*scale_y end max_x = math.max(max_x,_G.unpack(c_point_x)) max_y = math.max(max_y,_G.unpack(c_point_y)) min_x = math.min(min_x,_G.unpack(c_point_x)) min_y = math.min(min_y,_G.unpack(c_point_y)) c_point_x[1] = s_point_x*scale_x+base_pos_x c_point_y[1] = s_point_y*scale_y+base_pos_y for k = 2, 4, 1 do c_point_x[k] = point[i+1+(k-2)*2]*scale_x+base_pos_x c_point_y[k] = point[i+2+(k-2)*2]*scale_y+base_pos_y end s_point_x = point[i+5] s_point_y = point[i+6] i = i + 7 elseif point[i] == "l" then c_point_x[1] = s_point_x*scale_x c_point_y[1] = s_point_y*scale_y c_point_x[2] = point[i+1]*scale_x c_point_y[2] = point[i+2]*scale_y max_x = math.max(max_x,_G.unpack(c_point_x)) max_y = math.max(max_y,_G.unpack(c_point_y)) min_x = math.min(min_x,_G.unpack(c_point_x)) min_y = math.min(min_y,_G.unpack(c_point_y)) c_point_x[1] = s_point_x*scale_x+base_pos_x c_point_y[1] = s_point_y*scale_y+base_pos_y c_point_x[2] = point[i+1]*scale_x+base_pos_x c_point_y[2] = point[i+2]*scale_y+base_pos_y s_point_x = point[i+1] s_point_y = point[i+2] i = i + 3 else _G.aegisub.debug.out("Unknown drawing command. You can use only \"m\" , \"b\" , \"l\"^^;") i = #point+1 end c_t = 0 n = #c_point_x if n ~= 0 then while c_t <= 1 do m = m + 1 pos_x[m], pos_y[m] = Bezier(n,c_point_x,c_point_y,c_t) n_x, n_y = Bezier(n,c_point_x,c_point_y,c_t+0.1) dist = math.sqrt(math.abs(n_x-pos_x[m])^2+math.abs(n_y-pos_y[m])^2) c_t = c_t + max_space/dist*0.1 end end end maxloop(m) end retime("presyl",s_time+dur*(t^accel),s_time+dur*((t+1/m)^accel)+afterimage_dur) t = t + 1/m adjust_x = -(max_x - min_x) / 2 - min_x adjust_y = -(max_y - min_y) / 2 - min_y return string.format("\\move(%f,%f,%f,%f,%f,%f)",pos_x[j]+x_add,pos_y[j],pos_x[j]+x_blur+x_add,pos_y[j]+y_blur,afterimage_dur/2,afterimage_dur) end
Comment: 0,0:00:00.00,0:00:00.00,Default,shape,0,0,0,code once,shape="m 16 21 b 14 19 10 17 7 16 l 4 20 b 7 22 11 24 13 26 l 16 21 m 14 34 b 12 32 8 30 5 29 l 2 33 b 5 35 9 37 11 39 l 14 34 m 12 41 b 9 46 6 52 3 56 l 8 60 b 10 55 13 50 16 44 l 12 41 m 39 24 b 37 31 35 37 32 42 b 28 37 26 31 24 24 l 39 24 m 41 18 l 40 18 l 18 18 l 18 24 l 19 24 l 19 24 b 21 33 24 41 28 47 b 24 51 19 54 14 55 b 15 56 17 59 18 60 b 23 58 28 55 31 51 b 35 55 39 58 43 60 b 44 59 46 56 47 55 b 42 53 38 50 35 47 b 40 40 43 31 45 19 l 41 18 m 57 25 l 87 25 l 87 31 l 93 31 l 93 20 l 77 20 b 76 18 75 16 74 15 l 68 17 b 69 17 69 19 70 20 l 52 20 l 52 31 l 57 31 l 57 25 m 94 41 l 76 41 l 76 40 b 80 38 83 35 86 32 l 82 29 l 81 29 l 60 29 l 60 34 l 75 34 b 73 36 71 37 69 38 l 69 41 l 52 41 l 52 46 l 69 46 l 69 54 b 69 54 69 54 68 54 b 67 54 64 54 61 54 b 62 56 63 58 63 60 b 67 60 70 60 72 59 b 75 58 76 57 76 54 l 76 46 l 94 46 l 94 41 "
Comment: 0,0:00:00.00,0:00:00.00,Default,,0,0,0,template line noblank,{!Vector_Move(0,2000,3000,0,math.random(0,0),1,400,300,1,500,500,shape,0)!\p2\bord0\an7}m 19 4 b 23 8 23 15 19 19 b 15 23 8 23 4 19 b 0 15 0 8 4 4 b 8 0 15 0 19 4
Comment: 0,0:00:00.00,0:00:00.00,Default,,0,0,0,template line noblank,{\p1\pos(400,300)\an7\fscx500\fscy500\bord0\c&H7BFFEE&}!shape!
Comment: 0,0:00:00.00,0:00:07.23,Default,,0,0,0,karaoke,测试
感谢博主的分享,支持了。
技术文章,学习了。文章真长
感谢支持!如果学习Aegisub的话,建议搭配参考链接的视频一起~