貝塞爾風暴 - 超炫GABottleLoading效果
談到貝塞爾曲線,很多人會覺得高逼格、復雜、頭疼,實則不然,貝塞爾曲線經過android封裝,已經顯得嬌俏可愛,簡單好用,之前一些紅極一時的效果也均是由其打造,比如QQ的“一鍵退潮”效果、電子書曲面翻頁效果...... 現在咱們就用貝塞爾曲線一起從0到1打造一個擁有極致體驗、清秀靈動的GABottleLoading效果;
好了,不多吹NB了,老規矩先上一個原始效果圖:
看到這個效果,估計有人開噴:
“我擦,聽你吹半天NB,這個效果老子兩年前就看過了,github上早有了,垃圾......”
此時,沉穩優雅、帥氣逼人的GA哥在github上通過關鍵字搜索,兩個實現赫然出現在我的面前,看來天不助我,然后通過查看他們的實現,發現其中一個實現的很棒,老實說GA哥都沒有信心實現到如此完美,but看過之后發現他是直接加載gif,fuck, too young, too simple, 另一個呢?通過代碼實現,現在讓我們瞻仰下他實現的效果:
從效果上來看,基本實現了瓶身、波紋晃動,但真正復雜的氣泡與動態并傾斜的水面的脫離過程卻并未實現,而這才是GA哥感興趣的地方,此時天空響起一聲驚雷,GA哥閃亮登場;
首先,讓我們一起分解下這個動效,簡單來看,該效果可以分成以下幾個部分:
1.水滴從水面彈出和融入;
2.水面的波動;
3.瓶身的繪制;
接下來,咱們一起從以上三個內容逐個處理:
一、水滴從水面彈出和融入
正式分析之前,請和GA哥一起通過一個慢鏡頭看看其中一個水滴脫離水面的過程;
我擦,不看不知道,沒想到過程如此細膩!
是不是突然感覺這個動效沒那么簡單了?是不是有點難度了?尤其是水滴離開水面的過程中,水面還在不斷的變動,而整個水滴彈出和融入的過程都需要和水面柔和爽朗的連接;
俗話說,“擒賊先擒王”,咱們第一步就來搞定水滴的粘連出入過程!
首先我們來看一下過程分解圖(請關注左邊的水滴):
由上圖可以觀察到,到(4)的時候,水滴已經完全脫離了水面,只不過存在一定的粘連(由于水的張力);
接下來我們分析下水滴脫離水面的過程,為了更好的說明,將水面簡化為一個靜態的斜面,這樣更加直觀;
那么原始模型如下圖,其中斜線代表水面,圓代表水滴,是不是很簡單?
接下來我們需要考慮,如何處理水滴和水面的粘連效果,標題既然叫做貝塞爾曲線打造極致GABottleLoading效果,咱們肯定是使用貝塞爾曲線這一神器了,既然使用貝塞爾曲線,那么不用多說,就需要考慮起始點、終點、控制點這些核心數據;
從效果來看,起始點咱們可以直接從水滴上取,然而具體取到何處呢?咱們可以以水滴冒出水面的高度為基準,然后定義一個適當比例,以該比例計算具體數據點;
既然起始點在水滴上,那么終點毋庸置疑在水面上,具體取于何處呢?咱們可以采用如下方式(至于為何要這么取則是GA哥的思路):
使用一個矩形框框住水滴區域,使水滴距離左右兩邊 L1、L2,并且L1 == L2 ;
此時矩形框與水面形成交點w1、w2,咱們可以直接選取如圖所示w1、w2作為兩個終點,這兩個點即表示水滴由于張力而形成的拖尾和水面的接觸點;
經過以上思路,咱們畫出以下圖示:
看上面這張圖,其中L3為水面上點w1和w2的連接線,L4為經過圓心并且和L3垂直的直線,wd為L3與L4的交點,,Ct為圓最頂端數據點,C1、C2為垂直于L4的L5與圓環的交點;
咱們將輔助線都去掉,那么就得到如下的圖:
在圖上,C1、C2為起始點,W1、W2為終點;
好了,起始點、終點咱們定下了確定的方法,控制點呢?
且繼續看下圖;
圖中L6、L9分別為點w1及w2所在的水面的切線,L7、L8分別為C1及C2處的切線,q1為L6與L7的交點、q2為L8與L9的交點,q1與q2則為咱們找的兩個控制點;
到此,包括起始點、終點、控制點在內的貝塞爾曲線所需的核心數據咱們就都找到了,如下圖所示的6個點;
6個點、6個點、6個點,重要的事情說三遍......
然后咱們利用以上6個點繪制兩條二階貝塞爾曲線,形成相應拖尾粘連效果,具體效果圖如下:
我們把不需要的點去除,并填充上顏色,看看最后的效果:
那么這部分整體效果的結果如何?請看!
這個不夠直觀?那讓我們加上輔助點,請看!
- 圓上的白色的點從左往右分別是c1、c2,分別表示拖尾與圓的接觸點,即貝塞爾曲線的起始點;
- 圓兩側兩側紅色的點從左往右為分別為w1、w2,表示拖尾與水面的接觸點,即貝塞爾曲線的終點;
- 藍色點從左往右分別為q1、q2,分別表示左右兩側的控制點;
最后,圓完全脫離水面如下圖:
圓拖著拖尾上移:
最后拖尾斷裂:
最后水滴完全脫離,水面恢復平靜:
讓我們一起來看看整個過程:
ok,到此,水滴從水面彈出和融入的思路分析就此結束;
二、水面的波動分析
同樣,咱們先看下原始效果圖:
github上已實現效果圖:
沒有對比就沒有傷害,看起來是不是覺得原始效果圖要柔和自然很多?那么到底是什么原因呢?GA哥分析主要是以下兩點原因:
- 1.波動效果,原效果圖是一個減速過程,當水波達到最高點的時候速度變為了0,而對比圖是一直勻速的過程;
- 2.上面流動的水和下面靜止的水的連接處理有差異;
當然,以GA哥的尿性肯定是以原效果圖為目標,而當GA哥在PS中采用三階貝塞爾曲線去擬合的時候,發現還是存在一定的瑕疵,不能完全的擬合上;
最終,最右邊的連接弧度采用上圖所示數據作為參數,實現的效果如下:
我擦,連接處不夠柔順,此時GA哥采用了以下處理方案;
將波動的水面抬高,和底部靜止的水面保持一定的距離,然后采用二階貝塞爾曲線將兩者的連接處進行連接:
恩,上圖的效果還是可以接受的,讓我們看看動起來什么效果:
- 作者注:恩,此時如GA哥的秀發般飄逸了! - GAStudio哥
三、瓶身的繪制
瓶身繪制就是一個字——"扣",扣細節,然后達到各個接觸點比較完美的連接;
讓我們從左半部分的上方開始講起。
瓶口處的的彎角,一開始GA哥也是認為是一個半圓(180度),然后再連接直線。然而這樣做效果不是很好,所以GA哥采用四分之一圓環(90度),然后連接45度的直線,最后連接垂直的瓶嘴直線,效果如下圖:
- 路人甲:納尼?怎么有這么明顯的棱角?作為細致的GA哥,依舊沒有放過這個細節。
- 路人乙:敢問GA哥有什么有效的方案?使用Paint.Cap.ROUND?
- GA哥:No, No, No, Paint.Cap.ROUND 只對line的頭部有效,GA哥采用了將Paint的PathEffect設置成了CornerPathEffect,那么就會將直線和直線間的連接處,自動做了圓滑處理。
那么效果如何呢?請看下圖:
臥槽,好帥,好柔滑有木有!
此外, 瓶身連接處 (如下圖紅色標注處)也是需要注意的,要么計算準確,完美的連接;要么索性有一點缺口,采用arcTo繪制瓶身,此時缺口會自動連接上直線,再加上之前配置的CornerPathEffect,就會使得該處顯得自然:
接著 瓶身 采用圓弧繪制,從多少到多少角度都需要進行計算;
最后 底部 采用直線直接連接;
- GA哥: 恩,你們是不是覺得GA哥會說,右半部分和左半部分采用一樣的思路?
- 路人甲: 難道不是嗎?難道GA哥有啥高招?
- GA哥: 恩,GA哥這個人比較懶,所以什么事都想偷懶;
恩,我們都不用仔細觀察,這個瓶子是 左右對稱 的!所以直接反轉過來就行了哇!
關鍵代碼如下:
// Generate the right path Camera camera = new Camera(); Matrix matrix = new Matrix(); camera.save(); camera.rotateY(HALF_FULL_ANGLE); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-mViewRectF.centerX(), -mViewRectF.centerY()); matrix.postTranslate(mViewRectF.centerX(), mViewRectF.centerY()); Path rightBottlePath = new Path(); rightBottlePath.addPath(mBottlePath); mBottlePath.addPath(rightBottlePath, matrix);
總結
- GA哥:總結?總結啥呢?
- 路人甲:看看效果唄,看你吹了這么久,哈哈!
- 路人乙:贊同樓上的;
- 路人丙:贊同樓上的;
- 路人丁:贊同樓上的;
- ...
- GA哥:盛情難卻哇,那就獻丑了!
最后,附上GAStudio技術交流群和Github,喜歡的話歡迎follow和star:
來自:http://www.jianshu.com/p/93b0d948abf8