Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
塞爾曲線在計(jì)算機(jī)圖形學(xué)中被大量使用,通常可以產(chǎn)生平滑的曲線。如果您曾經(jīng)使用過Photoshop,則可能會發(fā)現(xiàn)名為“錨點(diǎn)”的工具,您可以在其中放置錨點(diǎn)并用它們繪制一些曲線,這些也是貝塞爾曲線。如果您使用了基于矢量的圖形SVG,這些也會使用貝塞爾曲線。讓我們看看它是如何工作的。
給定n + 1 個(gè)點(diǎn)(P0,…,Pn)稱為控制點(diǎn),這些點(diǎn)定義的貝塞爾曲線定義為:
eq. 1
其中B(t)稱為Bernstein多項(xiàng)式:
eq. 2
你會注意到這個(gè)伯恩斯坦多項(xiàng)式看起來很像牛頓二項(xiàng)式公式中的第k項(xiàng),也就是:
eq. 3
事實(shí)上,伯恩斯坦多項(xiàng)式就是(t + (1 - t))^n=1的展開式中的第k項(xiàng)。這就是為什么如果你把所有的Bi加到n,你會得到1。
二次貝塞爾曲線就是我們所說的有三個(gè)控制點(diǎn)的貝塞爾曲線,P(t)的階數(shù)是2。讓我們計(jì)算給定3個(gè)控制點(diǎn)的貝塞爾曲線,并探索一些我們可能會發(fā)現(xiàn)的特性!請記住,公式1適用于n+1個(gè)點(diǎn),所以在我們的例子中n=2。
eq. 4
注意,P(t)返回的不是一個(gè)數(shù)字,而是曲線上的一個(gè)點(diǎn)?,F(xiàn)在我們只需要選擇三個(gè)控制點(diǎn),然后在[0,1]范圍內(nèi)對曲線求值。我們可以在Python中很容易地做到這一點(diǎn)。
import numpy as np
import matplotlib.pyplot as plt
P0, P1, P2=np.array([
[0, 0],
[2, 4],
[5, 3]
])
# define bezier curve
P=lambda t: (1 - t)**2 * P0 + 2 * t * (1 - t) * P1 + t**2 * P2
# evaluate the curve on [0, 1] sliced in 50 points
points=np.array([P(t) for t in np.linspace(0, 1, 50)])
# get x and y coordinates of points separately
x, y=points[:,0], points[:,1]
# plot
plt.plot(x, y, 'b-')
plt.plot(*P0, 'r.')
plt.plot(*P1, 'r.')
plt.plot(*P2, 'r.')
plt.show()
您會注意到曲線從第一個(gè)控制點(diǎn)處開始,到最后一個(gè)控制點(diǎn)處結(jié)束。這個(gè)結(jié)果對任意數(shù)量的點(diǎn)都成立。由于t的取值范圍是從0到1,我們可以通過求P(t)在t=0和t=1時(shí)的值來證明這一點(diǎn)。使用eq.1:
eq. 5
eq. 6
因?yàn)槭菑腜0到P2,P1完全決定了曲線的形狀。移動(dòng)P1你可能會注意到:
貝塞爾曲線總是包含在控制點(diǎn)形成的多邊形中。這個(gè)多邊形因此被稱為控制多邊形,或者貝塞爾多邊形。這個(gè)屬性也適用于任意數(shù)量的控制點(diǎn),這使得它們在使用軟件時(shí)的操作非常直觀。
控制多邊形還具有以下特性:包含曲線的面積最小,稱為凸包。
貝塞爾曲線的一個(gè)有趣應(yīng)用是繪制一條通過一組預(yù)定義點(diǎn)的平滑曲線。之所以有趣,是因?yàn)镻(t)的公式產(chǎn)生點(diǎn),并且不是y=f(x)的形式,因此一個(gè)x可以具有多個(gè)y。。例如,我們可以這樣畫:
下面是如何使用公式1為任意數(shù)量的控制點(diǎn)編寫通用版本的Bezier曲線。
import numpy as np
import matplotlib.pyplot as plt
from math import factorial
def comb(n, k):
return factorial(n) // (factorial(k) * factorial(n - k))
def get_bezier_curve(points):
n=len(points) - 1
return lambda t: sum(
comb(n, i) * t**i * (1 - t)**(n - i) * points[i]
for i in range(n + 1)
)
def evaluate_bezier(points, total):
bezier=get_bezier_curve(points)
new_points=np.array([bezier(t) for t in np.linspace(0, 1, total)])
return new_points[:,0], new_points[:,1]
points=np.array([
[0, 0],
[-1, 3],
[4, 3],
[6, 0],
[7, 2.5]
])
x, y=points[:,0], points[:,1]
bx, by=evaluate_bezier(points, 50)
plt.plot(bx, by, 'b-')
plt.plot(x, y, 'r.')
plt.show()
運(yùn)行該P(yáng)ython程序,顯示如下圖形:
了這篇文章,你就不用在其他地方學(xué)習(xí)基本的動(dòng)效設(shè)計(jì)規(guī)則了。
當(dāng)元素的位置和狀態(tài)發(fā)生改變的時(shí)候,動(dòng)效的速度應(yīng)該足夠慢,維持足夠長的時(shí)間,讓用戶能夠注意到變化,但是同時(shí),又不能慢到需要用戶去等待。
大量的研究表明,動(dòng)效的最佳持續(xù)時(shí)長是200毫秒到500毫秒之間,這個(gè)研究數(shù)字是基于人腦的認(rèn)知方式和信息消化速度得出來的。任何低于100毫秒的動(dòng)效對于人的眼睛而言,幾乎都是瞬間,很難被識別出來,而超過1秒的動(dòng)效會讓人有遲滯感。
△ 界面中動(dòng)效持續(xù)時(shí)長
在手機(jī)這樣的移動(dòng)端設(shè)備上,按照 Material Design 的建議,動(dòng)效時(shí)長應(yīng)該控制在200~300毫秒之間。在平板電腦上,這個(gè)時(shí)長應(yīng)該延長大概30%,也就是說,時(shí)長應(yīng)該在400~450毫秒之間。
原因很簡單,屏幕尺寸越大,元素在發(fā)生位移的時(shí)候,跨越的距離越長,速度一定的情況下,時(shí)長自然越長。相應(yīng)的,在可穿戴設(shè)備的小屏幕上,這個(gè)時(shí)長應(yīng)該縮短30%,在150~200毫秒之間。
△ 移動(dòng)端設(shè)備的屏幕尺寸影響動(dòng)畫的持續(xù)時(shí)長
網(wǎng)頁動(dòng)效的處理方式也不一樣,由于我們習(xí)慣在瀏覽器中直接打開網(wǎng)頁,考慮到瀏覽器性能和大家的使用習(xí)慣,用戶對于瀏覽器中動(dòng)效變化速率的預(yù)期還是比較快的。相比于移動(dòng)端中的動(dòng)效速度,網(wǎng)頁中的速度會快上一倍,換句話說,就是動(dòng)效的持續(xù)時(shí)長應(yīng)該在150~200毫秒之間。如果持續(xù)時(shí)間太長,用戶會忍不住覺得網(wǎng)頁卡住了。
不過,如果你的網(wǎng)頁中所用的動(dòng)效并非功能性的,而是裝飾用的,或者用來吸引用戶的注意力,那么請忘記這個(gè)規(guī)則,在這種情況下,動(dòng)效可以更長。
更大的屏幕=更慢的動(dòng)效?絕不是如此!
請務(wù)必記住,無論是在什么平臺上,動(dòng)效的持續(xù)時(shí)長絕不是單純?nèi)Q于屏幕尺寸和運(yùn)動(dòng)距離,還取決于平臺特征、元素大小、功能設(shè)定等等。較小的元素或者較小的變化,相應(yīng)的動(dòng)效應(yīng)該更快一點(diǎn)。因此,大而復(fù)雜的元素動(dòng)效持續(xù)時(shí)間更長,看起來也更舒服一點(diǎn)。
大小相同的元素,在移動(dòng)的時(shí)候,移動(dòng)距離最短的元素,是最先停止下來的。
與較大的元素相比,較小的元素運(yùn)動(dòng)速度應(yīng)該更慢,因?yàn)橄嗤囊苿?dòng)距離,對于小元素而言,位移距離和自身大小比例倍數(shù)更大,相對偏移更遠(yuǎn)。
△ 動(dòng)效的持續(xù)時(shí)長還和元素大小、運(yùn)動(dòng)距離有關(guān)
動(dòng)效的運(yùn)動(dòng)規(guī)律要符合物理規(guī)律,當(dāng)元素運(yùn)動(dòng)到邊界,發(fā)生碰撞的時(shí)候,碰撞的「能量」最終是要均勻分?jǐn)傁聛淼?,而彈跳的特效在多?shù)情況下是不適合的,僅在特殊情況下適合使用。
△ 避免使用彈跳特效,它會分散用戶的注意力
元素的運(yùn)動(dòng)過程應(yīng)該是清晰的,盡量不要在運(yùn)動(dòng)中使用模糊的效果(是的,說的就是 AE 的模糊動(dòng)效愛好者們),模糊的動(dòng)效不適合在 UI界面中使用。
△ 不要在動(dòng)效中使用模糊效果
列表項(xiàng)(新聞列表、郵件列表等)所使用的動(dòng)效,在實(shí)際運(yùn)動(dòng)的過程中,項(xiàng)和項(xiàng)之間應(yīng)該有輕微的延遲,元素之間的延遲應(yīng)該控制在20~25毫秒之間,如果持續(xù)時(shí)間再長,可能會給人一種遲滯的觀感。
△ 列表項(xiàng)之間的延遲應(yīng)該在20~25毫秒
緩動(dòng)指的是物體在物理規(guī)則下,漸進(jìn)加速或減速的現(xiàn)象。在動(dòng)效中加入緩動(dòng)的效果能夠讓運(yùn)動(dòng)顯得更加自然,這是運(yùn)動(dòng)的基本原則之一。對于緩動(dòng),迪士尼的兩位關(guān)鍵性的動(dòng)畫大師 Ollie Johnston 和 Frank Thomas 在他們的著作《The Illusion of Life: Disney Animation》中有過非常詳盡的描述。
為了不讓動(dòng)效看起來機(jī)械或者人工痕跡太明顯,元素的運(yùn)動(dòng)應(yīng)該有漸進(jìn)加速和漸進(jìn)減速的特征,就像物理世界當(dāng)中其他的物體這樣。
勻速直線運(yùn)動(dòng)
不受任何物理力量的影響,勻速直線運(yùn)動(dòng)看起來是非常不自然的,尤其是對于人眼而言。
所有用來設(shè)計(jì)動(dòng)畫的應(yīng)用都會使用坐標(biāo)軸和曲線來闡述動(dòng)效的運(yùn)動(dòng)特征,我將嘗試闡述它們的含義,以及如何使用。坐標(biāo)軸的 X軸是實(shí)現(xiàn),而 Y軸則表示的唯一,換句話來說,如同我們在初中物理中所學(xué)到的,坐標(biāo)軸上的線條描述的是速度和加速度的特征。
下面所示的直線,表示速度是均勻的,也就是勻速直線運(yùn)動(dòng),物體在相同時(shí)間內(nèi)運(yùn)動(dòng)的距離是不變的。
△ 勻速直線運(yùn)動(dòng)的座標(biāo)圖
均勻的變化通常只會用在色彩的改變或者透明的改變上,一般來說,我們也可以讓背景元素均勻運(yùn)動(dòng),而前景元素保持不變,來呈現(xiàn)它的狀態(tài),就像上圖一樣。
緩動(dòng)加速曲線
通過曲線我們可以看到,物體開始時(shí)候的初速度比較低,運(yùn)動(dòng)緩慢,隨后速度逐漸增加,這意味著物體在加速運(yùn)動(dòng)。
△ 加速曲線
當(dāng)物體加速飛出屏幕的時(shí)候,可以使用這種加速曲線,比如界面中被用戶使用滑動(dòng)手勢甩出去的卡片。但是請記住,只有當(dāng)運(yùn)動(dòng)對象需要完全離開界面的時(shí)候才會這么使用,如果它還需要再回來的話,則不行。
△ 以加速運(yùn)動(dòng)將卡片扔出屏幕
動(dòng)畫曲線有助于正確傳達(dá)訊息,甚至表達(dá)情緒和感覺。在下面的案例當(dāng)中,我們可以看每個(gè)元素的運(yùn)動(dòng)位移是完全一樣的,所消耗的總時(shí)長也是一樣的,但是運(yùn)動(dòng)的速率變化是不同的,這一點(diǎn)也體現(xiàn)在曲線上,所表現(xiàn)出來的情緒也不同。
當(dāng)然,通過調(diào)整曲線,你能夠讓物體的運(yùn)動(dòng)軌跡盡可能接近現(xiàn)實(shí)世界。
緩動(dòng)減速曲線
當(dāng)元素從屏幕外運(yùn)動(dòng)到屏幕內(nèi)的時(shí)候,動(dòng)效應(yīng)該遵循這類曲線的運(yùn)動(dòng)特征。從全速進(jìn)入屏幕開始,速度降低,直到完全停止。
△ 減速曲線
減速曲線可以適用于多種不同的 UI控件和元素,包括從屏幕外進(jìn)入屏幕內(nèi)的的卡片、條目等。
△ 減速曲線案例
在這種曲線之下,物體從靜止開始加速,到達(dá)速度最高點(diǎn)之后開始減速直到靜止。這種類型的元素在 UI界面中最為常見,每當(dāng)你不知道要在動(dòng)效中使用哪種運(yùn)動(dòng)方式的時(shí)候,可以試試標(biāo)準(zhǔn)曲線。
△ 標(biāo)準(zhǔn)曲線
根據(jù) Material Design 的規(guī)范,最好使用不那么對稱的增速和減速的過程,讓動(dòng)效看起來更加真實(shí)。同時(shí)大家會更加在意運(yùn)動(dòng)的結(jié)果,曲線的末端,也就是運(yùn)動(dòng)結(jié)束的過程最好進(jìn)行適當(dāng)?shù)膹?qiáng)調(diào)。
換句話說就是減速過程持續(xù)的時(shí)長最好超過開始加速的時(shí)長,用戶將會更加清楚地觀察到運(yùn)動(dòng)的最終結(jié)果,從而更好地明白運(yùn)動(dòng)的終止?fàn)顟B(tài)。
△ 對稱和非對稱運(yùn)動(dòng)的差異
當(dāng)元素從屏幕的一個(gè)位置移動(dòng)到另外一個(gè)位置的時(shí)候,最好使用這種標(biāo)準(zhǔn)的緩動(dòng)曲線,這個(gè)過程中,盡量不要讓動(dòng)畫效果引人注意,不要使用戲劇化的效果。
△ 卡片元素從屏幕上運(yùn)動(dòng)的時(shí)候,不對稱的緩動(dòng)曲線
當(dāng)元素從屏幕上消失的時(shí)候,采用了相同的不對稱緩動(dòng)曲線,用戶同樣可以通過滑動(dòng)回到之前的位置。這個(gè)環(huán)節(jié)使用了抽屜式導(dǎo)航控件。
△ 抽屜式導(dǎo)航隨著緩動(dòng)曲線從屏幕上隱藏
從這些案例當(dāng)中,可以看出許多動(dòng)效的初學(xué)者對于運(yùn)動(dòng)規(guī)則的了解還不足。比如:下面的這個(gè)動(dòng)效,元素隨著減速曲線出現(xiàn),然后使用標(biāo)準(zhǔn)緩動(dòng)曲線消失。根據(jù) Material Design 的標(biāo)準(zhǔn),新出現(xiàn)的元素持續(xù)的時(shí)間應(yīng)該更長,因?yàn)樾枰嗟淖⒁饬Α?/p>
△ 導(dǎo)航菜單的出現(xiàn)和消失
貝賽爾曲線函數(shù) cubic-bezier是用來描述曲線的,它的名字前面之所以帶有 Cubic 是因?yàn)槊總€(gè)貝賽爾曲線的描述都是基于四個(gè)不同的參數(shù)來確定的。曲線的起點(diǎn)(0,0)和終點(diǎn)(1,1)在坐標(biāo)軸上的位置是已經(jīng)事先確定的。
為了簡化你對于貝賽爾曲線的理解,我們推薦兩個(gè)網(wǎng)站,分別是 easings.net 和 cubic-bezier.com ,前者包含了最常見的曲線的列表,你可以將他們復(fù)制到你的原型工具中,第二個(gè)網(wǎng)站為你提供了不同曲線的參數(shù),你可以直接在其中查看各種對象的移動(dòng)方式。
△ 不同類型的 cubic-bezier的曲線和參數(shù)
就像芭蕾舞的舞蹈編排一樣,動(dòng)畫效果也是需要編排的,它的主要目的是讓元素從一個(gè)狀態(tài)切換到下一個(gè)狀態(tài),自然過渡,讓用戶的注意力自然地被引導(dǎo)過去。
編排有兩種不同的方式:一種是均等交互,另一種是從屬交互。
均等交互意味著所有的元素和對象都遵循一個(gè)特定的編排的規(guī)則。
在這個(gè)實(shí)例當(dāng)中,所有的卡片都遵循著一個(gè)方向來引導(dǎo)用戶的注意力,自上到下地次第加載。相反,沒有按照這樣清晰的規(guī)則來加載,用戶的注意力會被分散,元素的外觀排布也會顯得比較糟糕。
△ 用戶的注意力應(yīng)該沿著一個(gè)流向來引導(dǎo)
至于表格式的布局,它相對就復(fù)雜一點(diǎn)。在這里,用戶的視線流向應(yīng)該是清晰的對角線方向,因此,逐個(gè)區(qū)塊次第出現(xiàn)是一個(gè)糟糕的設(shè)計(jì)。這樣的逐個(gè)顯示,一方面耗時(shí)太長,另一方面會讓用戶覺得元素的加載方式是鋸齒狀的,這種方式并不合理。
△ 沿著對角線加載
從屬交互指的是使用一個(gè)中心對象作為主體,來吸引用戶的注意力,而其他的元素從屬于它來逐步呈現(xiàn)。這樣的動(dòng)畫設(shè)計(jì)能夠創(chuàng)造更強(qiáng)的秩序感,讓主要的內(nèi)容更容易引起用戶的注意。
在其他的設(shè)計(jì)當(dāng)中,用戶很難搞清楚哪個(gè)才是主要的,因?yàn)樽⒁饬Ρ环稚⒘?。因此,如果要設(shè)置多個(gè)動(dòng)畫元素,應(yīng)該定義清楚誰為主,誰是中心,并且盡量按照從屬關(guān)系來次第呈現(xiàn)不同的子元素。
如果只有一個(gè)中心對象,那么其他的對象的運(yùn)動(dòng)方式都要受它制約,否則用戶分不清楚主次。
根據(jù) Material Design 的規(guī)定,當(dāng)元素不成比例地變幻尺寸的時(shí)候,它應(yīng)該沿著弧線運(yùn)動(dòng),而不是直線運(yùn)動(dòng),這樣有助于讓它看起來更加自然。所謂「不成比例」地變化指的是元素的長和寬的變化并不是按照相同比例來縮放或者變化的,換句話來說,變化的速度也不一樣。(比如:方形變成矩形)
△ 不成比例地改變對象外觀的時(shí)候,運(yùn)動(dòng)軌跡應(yīng)該是弧線的
相反,如果元素是按照比例改變大小的時(shí)候,應(yīng)該沿著直線移動(dòng),這樣不僅操作更加方便,而且更符合均勻變化的特征??匆幌抡鎸?shí)的案例,你會發(fā)現(xiàn)直線的運(yùn)動(dòng)軌跡會更加合理。
△ 成比例變化大小的時(shí)候,應(yīng)該沿著直線運(yùn)動(dòng)
當(dāng)元素不成比例放大的時(shí)候,運(yùn)動(dòng)軌跡是弧線,而這種弧線運(yùn)動(dòng)軌跡有兩種不同的呈現(xiàn)一種,一種軌跡是初始方向?yàn)榇怪狈较蚨\(yùn)動(dòng)結(jié)束時(shí)瞬間運(yùn)動(dòng)方向是水平的(Horizontal out),另外一種初始方向是水平方向而運(yùn)動(dòng)結(jié)束時(shí)瞬間運(yùn)動(dòng)方向是垂直的(Vertical out)。
那么怎么選取這個(gè)方向呢?
很簡單,元素運(yùn)動(dòng)曲線的方向,應(yīng)該是要向界面的主要運(yùn)動(dòng)方向的主軸靠攏重合。舉個(gè)例子,在下面的動(dòng)效當(dāng)中,整個(gè)界面的滾動(dòng)方向是上下滾動(dòng),主軸是縱向的。因此,當(dāng)卡片點(diǎn)擊之后被展開的時(shí)候,會先向右水平移動(dòng),并最終以垂直運(yùn)動(dòng)結(jié)束,運(yùn)動(dòng)的最終方向,切線是垂直的,也就和垂直方向的主軸重合了。
△ 元素按照弧線展開的時(shí)候,最終方向應(yīng)該和主軸重合
如果幾個(gè)不同的元素的運(yùn)動(dòng)軌跡相交,那么他們不能彼此穿越。如果每個(gè)元素都必須通過某個(gè)交點(diǎn),抵達(dá)另外一個(gè)位置,那么應(yīng)該次第減速,依次通過這個(gè)點(diǎn),給彼此留出足夠的空間。另外一種選擇,是元素不相交,而是像實(shí)體一樣在靠近的時(shí)候,彼此推開。
為什么?
因?yàn)槲覀兺ǔ<俣ń缑嬷兴械脑囟嘉挥谕粋€(gè)平面當(dāng)中。
在運(yùn)動(dòng)過程中,元素不應(yīng)彼此穿越,而應(yīng)該互相留出空間。
但是這一點(diǎn)也不是一成不變的。在比較擁擠的界面當(dāng)中,某個(gè)元素可以「越過」其他的元素,它同樣沒有穿過其他的元素消失,而是單純的移動(dòng)。這一點(diǎn)從某種意義上也是延續(xù)自我們?nèi)粘5奈锢硪?guī)律,只不過我們會默認(rèn)界面中的元素在這個(gè)情況下?lián)碛辛烁叨冗@樣的屬性。
△ 元素可以越過其他的元素運(yùn)動(dòng)
我們總結(jié)了這么多動(dòng)效運(yùn)動(dòng)的規(guī)則和原則,從某種意義上還是延續(xù)自我們對于物理世界的認(rèn)知,摩擦力和加速度在虛擬界面中以另外的方式續(xù)存著。模仿現(xiàn)實(shí)世界的界面讓我們對于界面的秩序有更清晰的認(rèn)知,允許我們更輕松的了解和訪問界面的內(nèi)容。
如果動(dòng)效按照正確的方式來設(shè)計(jì),它應(yīng)該是不顯著,且不會分散用戶注意力的。如果不是這樣,那么你需要讓動(dòng)效更微妙一點(diǎn),實(shí)在不行甚至需要將它移除。動(dòng)效不應(yīng)該成為影響用戶操控界面的障礙,或者轉(zhuǎn)移注意力的存在。
當(dāng)然,即使是遵循這么多規(guī)律,動(dòng)效的設(shè)計(jì)依然是一門藝術(shù),而非單純的科學(xué),多做測試多摸索總是有必要的。
原文作者:Taras Skytskyi
原文鏈接:https://uxdesign.cc/the-ultimate-guide-to-proper-use-of-animation-in-ux-10bd98614fa9
譯文作者:陳子木
譯文鏈接:https://www.uisdc.com/ultimate-guide-to-ui-animation
本文由 @陳子木 授權(quán)發(fā)布于人人都是產(chǎn)品經(jīng)理,未經(jīng)作者許可,禁止轉(zhuǎn)載
題圖作者提供
塞爾曲線是自然幾何形狀的數(shù)學(xué)近似。我們使用它們來表示一條曲線,該曲線具有盡可能少的信息并具有很高的靈活性。
與更抽象的數(shù)學(xué)概念不同,貝塞爾曲線是為工業(yè)設(shè)計(jì)而創(chuàng)建的。它們是圖形軟件行業(yè)中流行的工具。
它們依賴于插值(我在上一篇文章中提過),結(jié)合了多個(gè)步驟以創(chuàng)建平滑曲線。為了更好地了解貝塞爾曲線的工作原理,讓我們從其最簡單的形式開始:二次貝塞爾曲線。
取三點(diǎn),這是二次貝塞爾曲線起作用的最低要求:
為了在它們之間繪制一條曲線,我們首先使用0到1范圍內(nèi)的值,在由三個(gè)點(diǎn)組成的兩個(gè)線段的每個(gè)頂點(diǎn)的兩個(gè)頂點(diǎn)上逐步進(jìn)行插值。這使我們在改變線段值時(shí)沿著線段移動(dòng)兩個(gè)點(diǎn)的t從0到1。
func _quadratic_bezier(p0: Vector2, p1: Vector2, p2: Vector2, t: float):
var q0=p0.linear_interpolate(p1, t)
var q1=p1.linear_interpolate(p2, t)
然后q0,我們進(jìn)行插值并q1獲得r沿曲線移動(dòng)的單個(gè)點(diǎn)。
var r=q0.linear_interpolate(q1, t)
return r
這種類型的曲線稱為二次貝塞爾曲線。
(圖片來源:維基百科)
在前面的示例的基礎(chǔ)上,我們可以通過在四個(gè)點(diǎn)之間進(jìn)行插值來獲得更多控制。
我們首先使用的功能與四個(gè)參數(shù)取四點(diǎn)作為輸入, p0,p1,p2和p3:
func _cubic_bezier(p0: Vector2, p1: Vector2, p2: Vector2, p3: Vector2, t: float):
我們對每個(gè)點(diǎn)應(yīng)用線性插值以將其減少到三個(gè):
var q0=p0.linear_interpolate(p1, t)
var q1=p1.linear_interpolate(p2, t)
var q2=p2.linear_interpolate(p3, t)
然后,我們將三點(diǎn)簡化為兩點(diǎn):
var r0=q0.linear_interpolate(q1, t)
var r1=q1.linear_interpolate(q2, t)
并給一個(gè):
var s=r0.linear_interpolate(r1, t)
return s
這是全部功能:
func _cubic_bezier(p0: Vector2, p1: Vector2, p2: Vector2, p3: Vector2, t: float):
var q0=p0.linear_interpolate(p1, t)
var q1=p1.linear_interpolate(p2, t)
var q2=p2.linear_interpolate(p3, t)
var r0=q0.linear_interpolate(q1, t)
var r1=q1.linear_interpolate(q2, t)
var s=r0.linear_interpolate(r1, t)
return s
結(jié)果將是在所有四個(gè)點(diǎn)之間插值的平滑曲線:
(圖片來源:維基百科)
==注意==
三次貝塞爾曲線插值在3D中的效果相同,只是使用Vector3 代替Vector2。
以立方貝塞爾曲線為基礎(chǔ),我們可以更改兩個(gè)點(diǎn)的工作方式以自由控制曲線的形狀。而是具有p0,p1,p2 和p3,我們將它們存儲為:
這樣,我們有兩個(gè)點(diǎn)和兩個(gè)控制點(diǎn),它們是相對于各個(gè)點(diǎn)的相對向量。如果您以前使用過圖形或動(dòng)畫軟件,則可能看起來很熟悉:
這就是圖形軟件如何向用戶顯示Bezier曲線,以及它們在Godot中的工作方式和外觀。
有兩個(gè)包含曲線的對象:Curve3D和Curve2D(分別用于3D和2D)。
它們可以包含多個(gè)點(diǎn),從而可以使用更長的路徑。也可以將它們設(shè)置為節(jié)點(diǎn):Path和Path2D(也分別用于3D和2D):
但是,使用它們可能并不十分明顯,因此以下是Bezier曲線最常見用例的描述。
僅評估它們可能是一種選擇,但是在大多數(shù)情況下,它不是很有用。 貝塞爾曲線的最大缺點(diǎn)是,如果以恒定速度從t=0到t=1遍歷它們,則實(shí)際插補(bǔ)將不會以恒定速度移動(dòng)。 速度也是點(diǎn)p0,p1,p2和p3之間距離的插值,并且沒有數(shù)學(xué)上簡單的方法來以恒定速度遍歷曲線。
讓我們用下面的偽代碼做一個(gè)簡單的例子:
var t=0.0
func _process(delta):
t +=delta
position=_cubic_bezier(p0, p1, p2, p3, t)
如您所見,即使t以恒定速度增加,圓的速度(以每秒像素為單位)也會變化。這使得貝塞爾曲線難以在開箱即用的情況下使用。
繪制貝塞爾曲線(或基于曲線的對象)是一種非常常見的用例,但這也不容易。在幾乎任何情況下,貝塞爾曲線都需要轉(zhuǎn)換為某種線段。但是,這通常很困難,而又不創(chuàng)建大量的代碼。
原因是曲線的某些部分(特別是拐角)可能需要大量的點(diǎn),而其他部分可能不需要:
此外,如果兩個(gè)控制點(diǎn)都是0, 0(請記住它們是相對矢量),則貝塞爾曲線將只是一條直線(因此繪制大量的點(diǎn)將是浪費(fèi)的)。
在繪制貝塞爾曲線之前,需要進(jìn)行細(xì)分。這通常通過遞歸或分而治之的功能來完成,該功能可以分割曲線,直到曲率量小于某個(gè)閾值為止。
的曲線類通過提供這種 Curve2D.tessellate()函數(shù)(其接收可選stages的遞歸和角度tolerance參數(shù))。這樣,基于曲線繪制對象就更容易了。
曲線的最后一個(gè)常見用例是遍歷它們。由于前面提到的有關(guān)恒速的內(nèi)容,這也很困難。
為了使此操作更容易,需要將曲線烘焙到等距的點(diǎn)。這樣,它們可以通過常規(guī)插值進(jìn)行近似(可以通過三次選項(xiàng)進(jìn)一步改進(jìn))。為此,只需將Curve.interpolate_baked()方法與Curve2D.get_baked_length()一起使用 。第一次調(diào)用它們中的任何一個(gè)都會在內(nèi)部烘焙曲線。
然后,可以使用以下偽代碼完成恒速遍歷:
var t=0.0
func _process(delta):
t +=delta
position=curve.interpolate_baked(t * curve.get_baked_length(), true)
然后,輸出將以恒定速度移動(dòng):
*請認(rèn)真填寫需求信息,我們會在24小時(shí)內(nèi)與您取得聯(lián)系。