成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

《每周一點canvas動畫》——3D點線與水波動畫

jaysun / 1534人閱讀

摘要:在數(shù)學(xué)上,遞推關(guān)系,也就是差分方程,是一種遞推地定義一個序列的方程式序列的每一項目是定義為前一項的函數(shù)。

《每周一點canvas動畫》——差分函數(shù)的妙用

每周一點canvas動畫代碼文件

好像上次更新還是十一前,這唰唰唰的就過去大半個月了,現(xiàn)在才更新實在不好意思。這次我們不涉及canvas 3D的內(nèi)容,主要分享一個比較炫的動畫效果,可以算是上一篇文章《每周一點canvas動畫》——3D點線與水波動畫的加強版。動畫效果來自codePen。在這篇文章中我們就分析這種效果是如何實現(xiàn)的,如果你對源碼比較懵逼,相信看完解析就會恍然大悟。先上效果圖:

![### 1.原理分析
相比與上篇文章][2]中簡陋的水波動畫的效果,本文的動畫效果不僅能夠和鼠標(biāo)進(jìn)行交互,而且波浪的形成更加自然,更加符合物理規(guī)律。整個動畫的形成過程就如動圖中所展示的那樣,在液面的位置點擊鼠標(biāo),此處的液面就會有一個比較大的起伏,然后此處的震動會向兩邊傳播,隨著能量的衰減,后面的震動幅度會越來越下,最后能量衰減到零,頁面趨于平靜。聽上去是不是很玄乎,感覺很高深!毛主席告訴我們千萬不要被物體的表面現(xiàn)象所迷惑(誰知道是誰說的呢o(^▽^)o)。下面我們就來一步一步的分析,這其中的原理。

首先,在靜止?fàn)顟B(tài)下我們可以看到整個液面就相當(dāng)于是個矩形。而當(dāng)我們點擊液面的位置時,這個矩形就發(fā)生了相應(yīng)的變化。但其實并不是整個矩形都發(fā)生了變化,而只是矩形的上邊發(fā)生了變化。那是如何做到僅僅讓矩形的上邊發(fā)生變化的呢?秘訣就在矩形的上邊并不是簡單的從左邊的點lineTo()到右邊的點。而是由很多的點lineTo()組成。這樣講可能不太好理解,看圖說話:


在上部我們設(shè)置了很多的點,這些點的縱坐標(biāo)都是一樣的,只是在水平方向相隔一定的間距。這樣在靜止的狀態(tài)下,我們就可以它看見與普通的矩形別無二致。而改變這些點的位置時我們就能同時改變矩形的形狀,從而形成不同的效果。

2.差分方程

說到差分方程也許很多人會頭疼,不過也沒本法,疼就疼會吧!這個知識點在高數(shù)里講微分方程那一節(jié),如果不明白,就算了吧!記住下面的用法也不錯,不過為了逼格我們還是簡單的介紹下。

在數(shù)學(xué)上,遞推關(guān)系(recurrence relation),也就是差分方程(difference equation),是一種遞推地定義一個序列的方程式:序列的每一項目是定義為前一項的函數(shù)。某些簡單定義的遞推關(guān)系式可能會表現(xiàn)出非常復(fù)雜的(混沌的)性質(zhì),他們屬于數(shù)學(xué)中的非線性分析領(lǐng)域。

記住一點,序列的每一項是定義為前一項的函數(shù),我們用的就是這個原理。他的圖像如果用matalab來繪制就是下面這樣:

不是特別像水波。我們要做的就是讓那一堆點按照這樣的波形去排列。

3.代碼實現(xiàn) 1.準(zhǔn)備工作

下面就到了大家最喜歡的代碼時間。首先,我們創(chuàng)建一個點類Vertexes, 它的作用就是定義并更新那一堆點,代碼在vertex.js中,如下:

function Vertex(x,y,baseY){
        this.baseY = baseY;         //基線
        this.x = x;                 //點的坐標(biāo)
        this.y = y;            
        this.vy = 0;                //豎直方向的速度
        this.targetY = 0;           //目標(biāo)位置
        this.friction = 0.15;       //摩擦力
        this.deceleration = 0.95;   //減速
    }
//y坐標(biāo)更新
Vertex.prototype.updateY = function(diffVal){
        this.targetY = diffVal + this.baseY;   //改變目標(biāo)位置
        this.vy += (this.targetY - this.y);       //速度
        this.vy *= this.deceleration;
        this.y += this.vy * this.friction;     //改變坐標(biāo)豎直方向的位置
    }

我們要用這個函數(shù)去創(chuàng)建那一堆點。回到我們的主文件index.js中。我們先初始化一些要用的東西:

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    W = window.innerWidth;
    H = window.innerHeight;

    canvas.width = W;
    canvas.height = H;

var color1 = "#6ca0f6",    //矩形1的顏色
    color2 = "#367aec";   //矩形2的顏色
    
var vertexes = [],    //頂點坐標(biāo)
    verNum = 250,     //頂點數(shù)
    diffPt = [],      //差分值
    

然后,創(chuàng)建點并把它push進(jìn)vertexes中,同時也創(chuàng)建相應(yīng)數(shù)量的差分值,同樣把它放到diffPt數(shù)組中,這樣每個點都有了對應(yīng)的差分值。

for(var i=0; i

結(jié)果是,每個頂點的y坐標(biāo)都在(H/2)的高度,水平坐標(biāo)每隔一定的間隔取一個點。在這里是每隔4.5個像素取一個點,這與你canvas的寬度和點的數(shù)目有關(guān)。這樣我們就把點創(chuàng)建完成了,來繪制一下看看效果。

![代碼如下:

functio][6]n draw(){
        
        //矩形1
        ctx.save()
        ctx.fillStyle = color1;
        ctx.beginPath();
        ctx.moveTo(0, H);
        ctx.lineTo(vertexes[0].x, vertexes[0].y);
        for(var i=1; i

就像你看到的那樣此時我們的液面完全是靜止的(因為沒更新點嘛)。之所以要繪制兩個矩形,你看看效果圖就明白了,只是為了更好看,你完全可以繪制第三層,第四層。下面我們就來更新這些點的坐標(biāo)。

2.核心代碼

點的更新我們放在了update函數(shù)中。首先,我們設(shè)置一個初始的震蕩點,緩沖變量初始差分值。

var vPos = 125;  //震蕩點
var dd = 15;     //緩沖
var autoDiff = 1000;  //初始差分值

這里的震蕩點就是我們的起震位置,意思是vertexes中的第125號點開始起震,它對應(yīng)的差分值就是autoDiff。它的改變會引起其他點的變化,從而達(dá)到更新其他差分值的效果。

function update(){
        autoDiff -= autoDiff*0.9;        //1
        diffPt[vPos] = autoDiff;         

        //左側(cè)
        for(var i=vPos-1; i>0; i--){     //2
            var d = vPos-i;
            if(d > dd){
                d=dd;
            }
            diffPt[i]-=(diffPt[i] - diffPt[i+1])*(1-0.01*d);
        }
        //右側(cè)
        for(var i=vPos+1; idd){
                d=dd;
            }
            diffPt[i] -= (diffPt[i] - diffPt[i-1])*(1-0.01*d);
        }

        //更新Y坐標(biāo)
        for(var i=0; i

現(xiàn)在我們對上面的部分做詳細(xì)解釋:
代碼1: 我們設(shè)置了起震位置的差分偏移量為autoDiff=100,注意autoDiff -= autoDiff*0.9;, 也就是說它的值每一幀都會變化。

代碼2:為起震位置的左邊,主要關(guān)注diffPt[i]-=(diffPt[i] - diffPt[i+1])*(1-0.01*d);這一行。i的起始位置為124,默認(rèn)差分值為0。稍作簡單推算,你會發(fā)現(xiàn),經(jīng)過更新后第124號點的差分值為99,同理第123號為97.02。以此類推,我們就可以得到第一幀的所有點的差分值。右邊同理。

代碼4:在得到第一幀的差分值后就該調(diào)用每個點的更新函數(shù)了,并且傳入計算好的差分值。形成的效果如下圖所示

看一下updateY函數(shù),我們把目標(biāo)位置targetY設(shè)置為差分值diffVal和基線baseY的和。然后,通過距離計算需要運動的速度vy,最后將速度作用于點的縱坐標(biāo)。這一段是不是與彈性動畫緩動動畫那一節(jié)很相似呢?

在緩沖系數(shù)dd的作用下,兩側(cè)的波會在擴散的過程中越來越小,最后趨近于0.我們也是通過這個變量去控制液體的粘度系數(shù),達(dá)到粘稠度高的物體擴散的越緩慢并且起伏比較低,粘稠度低的物體擴散迅速但起伏大的效果。

隨后,因為autoDiff的不斷衰減,不同幅值波形的疊加形成波浪效果,最終衰減到0.液面也就趨于平靜了。

現(xiàn)在,我們把update()和draw()放入動畫循環(huán)中你就會看到水波起伏然后趨于平靜的效果。

(function drawframe(){
        ctx.clearRect(0, 0, W, H);
        window.requestAnimationFrame(drawframe, canvas);
        update()
        draw();
    })()
3.鼠標(biāo)交互

上面的代碼已經(jīng)實現(xiàn)了波浪動畫的效果,但是震蕩完成后就平靜了,不會再發(fā)生震蕩的效果。這一步我們就來實現(xiàn)點哪,哪震的效果。實現(xiàn)的思路很簡單:水波之所以區(qū)域平靜是因為起震位置的差分值不斷衰減的結(jié)果,我們只需要在點擊鼠標(biāo)的位置重設(shè)autoDiff就可以了。此外,起震點的位置也要變成鼠標(biāo)點擊的位置。代碼如下:

canvas.addEventListener("mousedown", function(e){
        var mouse = {x:null, y:null};

        if(e.pageX||e.pageY){
            mouse.x = e.pageX;
            mouse.y = e.pageY;
        }else{
            mouse.x = e.clientX + document.body.scrollLeft +document.documentElement.scrollLeft;
            mouse.y = e.clientY + document.body.scrollTop +document.documentElement.scrollTop;
        }

        //重設(shè)差分值
        if(mouse.y>(H/2-50) && mouse.y<(H/2 +50)){
            autoDiff = 1000;
            vPos = 1 + Math.floor((verNum - 2) * mouse.x / W);
            diffPt[vPos] = autoDiff;
        }

        console.log(mouse.x, mouse.y)

    }, false)

在獲取鼠標(biāo)位置這里應(yīng)該注意一點,我們沒有減去canvas的偏移量,這是因為在這里canvas做的是全屏設(shè)置。所以,如果你的畫布并不是全屏大小,建議你使用我們的utils.js文件中的方法captureMouse來獲取鼠標(biāo)的坐標(biāo)。

另外在判斷鼠標(biāo)是否點擊在了液面上,我們設(shè)定了一個比較寬的范圍,上下共100px。這樣做的目的是讓用戶很容易就能觸發(fā)這個事件,而不是只在頁面那唯一的一個值上才能觸發(fā)。這種做法相信你以前做過,對于比較小的物體我們會遮罩一個大一些的透明物體,然后在該物體上做事件的觸發(fā),便于用戶操作。

其他的顏色改變等細(xì)小功能就不做過多的介紹了,see you?。?!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/80485.html

相關(guān)文章

  • 周一canvas動畫》——差分函數(shù)的妙用

    摘要:在數(shù)學(xué)上,遞推關(guān)系,也就是差分方程,是一種遞推地定義一個序列的方程式序列的每一項目是定義為前一項的函數(shù)。某些簡單定義的遞推關(guān)系式可能會表現(xiàn)出非常復(fù)雜的混沌的性質(zhì),他們屬于數(shù)學(xué)中的非線性分析領(lǐng)域。 每周一點canvas動畫代碼文件 好像上次更新還是十一前,這唰唰唰的就過去大半個月了,現(xiàn)在更新我也沒什么不好意思的。這次我們不涉及canvas 3D的內(nèi)容,主要分享一個比較炫的動畫效果,可以算...

    meislzhua 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<