《每周一点canvas动画》——3d点线与水波动画(代码片段)

10manongit 10manongit     2023-03-17     476

关键词:

《每周一点canvas动画》——差分函数的妙用

每周一点canvas动画代码文件

好像上次更新还是十一前,这唰唰唰的就过去大半个月了,现在才更新实在不好意思。这次我们不涉及canvas 3D的内容,主要分享一个比较炫的动画效果,可以算是上一篇文章《每周一点canvas动画》——3D点线与水波动画的加强版。动画效果来自codePen。在这篇文章中我们就分析这种效果是如何实现的,如果你对源码比较懵逼,相信看完解析就会恍然大悟。先上效果图:

技术图片

![### 1.原理分析
相比与上篇文章][2]中简陋的水波动画的效果,本文的动画效果不仅能够和鼠标进行交互,而且波浪的形成更加自然,更加符合物理规律。整个动画的形成过程就如动图中所展示的那样,在液面的位置点击鼠标,此处的液面就会有一个比较大的起伏,然后此处的震动会向两边传播,随着能量的衰减,后面的震动幅度会越来越下,最后能量衰减到零,页面趋于平静。听上去是不是很玄乎,感觉很高深!毛主席告诉我们千万不要被物体的表面现象所迷惑(谁知道是谁说的呢o(^▽^)o)。下面我们就来一步一步的分析,这其中的原理。

首先,在静止状态下我们可以看到整个液面就相当于是个矩形。而当我们点击液面的位置时,这个矩形就发生了相应的变化。但其实并不是整个矩形都发生了变化,而只是矩形的上边发生了变化。那是如何做到仅仅让矩形的上边发生变化的呢?秘诀就在矩形的上边并不是简单的从左边的点lineTo()到右边的点。而是由很多的点lineTo()组成。这样讲可能不太好理解,看图说话:

技术图片
在上部我们设置了很多的点,这些点的纵坐标都是一样的,只是在水平方向相隔一定的间距。这样在静止的状态下,我们就可以它看见与普通的矩形别无二致。而改变这些点的位置时我们就能同时改变矩形的形状,从而形成不同的效果。

2.差分方程

说到差分方程也许很多人会头疼,不过也没本法,疼就疼会吧!这个知识点在高数里讲微分方程那一节,如果不明白,就算了吧!记住下面的用法也不错,不过为了逼格我们还是简单的介绍下。

在数学上,递推关系(recurrence relation),也就是差分方程(difference equation),是一种递推地定义一个序列的方程式:序列的每一项目是定义为前一项的函数。某些简单定义的递推关系式可能会表现出非常复杂的(混沌的)性质,他们属于数学中的非线性分析领域。

记住一点,序列的每一项是定义为前一项的函数,我们用的就是这个原理。他的图像如果用matalab来绘制就是下面这样:

技术图片不是特别像水波。我们要做的就是让那一堆点按照这样的波形去排列。

3.代码实现

1.准备工作

下面就到了大家最喜欢的代码时间。首先,我们创建一个点类Vertexes, 它的作用就是定义并更新那一堆点,代码在vertex.js中,如下:

function Vertex(x,y,baseY)
        this.baseY = baseY;         //基线
        this.x = x;                 //点的坐标
        this.y = y;            
        this.vy = 0;                //竖直方向的速度
        this.targetY = 0;           //目标位置
        this.friction = 0.15;       //摩擦力
        this.deceleration = 0.95;   //减速
    
//y坐标更新
Vertex.prototype.updateY = function(diffVal)
        this.targetY = diffVal + this.baseY;   //改变目标位置
        this.vy += (this.targetY - this.y);       //速度
        this.vy *= this.deceleration;
        this.y += this.vy * this.friction;     //改变坐标竖直方向的位置
    

我们要用这个函数去创建那一堆点。回到我们的主文件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 = [],    //顶点坐标
    verNum = 250,     //顶点数
    diffPt = [],      //差分值
    

然后,创建点并把它pushvertexes中,同时也创建相应数量的差分值,同样把它放到diffPt数组中,这样每个点都有了对应的差分值。

for(var i=0; i<verNum; i++)
    vertexes[i] = new Vertex(W/(verNum-1)*i, H/2, H/2);
    diffPt[i] = 0;                                         //初始值都为0

结果是,每个顶点的y坐标都在(H/2)的高度,水平坐标每隔一定的间隔取一个点。在这里是每隔4.5个像素取一个点,这与你canvas的宽度和点的数目有关。这样我们就把点创建完成了,来绘制一下看看效果。
技术图片

![代码如下:

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<vertexes.length; i++)
            ctx.lineTo(vertexes[i].x, vertexes[i].y);
        
        ctx.lineTo(W,H);
        ctx.lineTo(0,H);
        ctx.fill();
        ctx.restore();
        
        //矩形2
        ctx.save();
        ctx.fillStyle = color2;
        ctx.beginPath();
        ctx.moveTo(0, H);
        ctx.lineTo(vertexes[0].x, vertexes[0].y+5);
        for(var i=1; i<vertexes.length; i++)
            ctx.lineTo(vertexes[i].x, vertexes[i].y+5);
        
        ctx.lineTo(W, H);
        ctx.lineTo(0, H);
        ctx.fill();
        ctx.restore();

就像你看到的那样此时我们的液面完全是静止的(因为没更新点嘛)。之所以要绘制两个矩形,你看看效果图就明白了,只是为了更好看,你完全可以绘制第三层,第四层。下面我们就来更新这些点的坐标。

2.核心代码

点的更新我们放在了update函数中。首先,我们设置一个初始的震荡点,缓冲变量初始差分值

var vPos = 125;  //震荡点
var dd = 15;     //缓冲
var autoDiff = 1000;  //初始差分值

这里的震荡点就是我们的起震位置,意思是vertexes中的第125号点开始起震,它对应的差分值就是autoDiff。它的改变会引起其他点的变化,从而达到更新其他差分值的效果。

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

        //左侧
        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);
        
        //右侧
        for(var i=vPos+1; i<verNum; i++)   //3
            var d = i-vPos;
            if(d>dd)
                d=dd;
            
            diffPt[i] -= (diffPt[i] - diffPt[i-1])*(1-0.01*d);
        

        //更新Y坐标
        for(var i=0; i<vertexes.length; i++)  //4
            vertexes[i].updateY(diffPt[i]);
        
    

现在我们对上面的部分做详细解释:
代码1: 我们设置了起震位置的差分偏移量为autoDiff=100,注意autoDiff -= autoDiff*0.9;, 也就是说它的值每一帧都会变化。

代码2:为起震位置的左边,主要关注diffPt[i]-=(diffPt[i] - diffPt[i+1])*(1-0.01*d);这一行。i的起始位置为124,默认差分值为0。稍作简单推算,你会发现,经过更新后第124号点的差分值为99,同理第123号为97.02。以此类推,我们就可以得到第一帧的所有点的差分值。右边同理。

代码4:在得到第一帧的差分值后就该调用每个点的更新函数了,并且传入计算好的差分值。形成的效果如下图所示
技术图片

看一下updateY函数,我们把目标位置targetY设置为差分值diffVal和基线baseY的和。然后,通过距离计算需要运动的速度vy,最后将速度作用于点的纵坐标。这一段是不是与弹性动画缓动动画那一节很相似呢?

在缓冲系数dd的作用下,两侧的波会在扩散的过程中越来越小,最后趋近于0.我们也是通过这个变量去控制液体的粘度系数,达到粘稠度高的物体扩散的越缓慢并且起伏比较低,粘稠度低的物体扩散迅速但起伏大的效果。

随后,因为autoDiff的不断衰减,不同幅值波形的叠加形成波浪效果,最终衰减到0.液面也就趋于平静了

现在,我们把update()和draw()放入动画循环中你就会看到水波起伏然后趋于平静的效果。

(function drawframe()
        ctx.clearRect(0, 0, W, H);
        window.requestAnimationFrame(drawframe, canvas);
        update()
        draw();
    )()

3.鼠标交互

上面的代码已经实现了波浪动画的效果,但是震荡完成后就平静了,不会再发生震荡的效果。这一步我们就来实现点哪,哪震的效果。实现的思路很简单:水波之所以区域平静是因为起震位置的差分值不断衰减的结果,我们只需要在点击鼠标的位置重设autoDiff就可以了。此外,起震点的位置也要变成鼠标点击的位置。代码如下:

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;
        

        //重设差分值
        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)

在获取鼠标位置这里应该注意一点,我们没有减去canvas的偏移量,这是因为在这里canvas做的是全屏设置。所以,如果你的画布并不是全屏大小,建议你使用我们的utils.js文件中的方法captureMouse来获取鼠标的坐标。

另外在判断鼠标是否点击在了液面上,我们设定了一个比较宽的范围,上下共100px。这样做的目的是让用户很容易就能触发这个事件,而不是只在页面那唯一的一个值上才能触发。这种做法相信你以前做过,对于比较小的物体我们会遮罩一个大一些的透明物体,然后在该物体上做事件的触发,便于用户操作。

其他的颜色改变等细小功能就不做过多的介绍了,see you!!!

《每周一点canvas动画》——修改增强版

...本周已经开始对删除的文章着手回复,目前进度如下:《每周一点canvas动画》——序《每周一点canvas动画》——用户交户《每周一点canvas动画》——三角函数《每周一点canvas 查看详情

《每周一点canvas动画》——用户交互(代码片段)

用户交互也许是我们学习canvas动画中首先需要掌握的部分。毕竟,如果没有交互或者向动画中做一些动态的输入,那么这跟看电影有什么区别呢?用户交互基于事件,一般来说包括:鼠标事件,触摸事件和键盘事件。1、事件和... 查看详情

《每周一点canvas动画》——三角函数(代码片段)

本节主要内容有:三角函数介绍常用三角函数解析鼠标跟随角度旋转看到三角函数,勾股定理这样的数学名词是不是有种双腿打颤的感觉啊!好吧,就算你已经吓尿了,也不能否认我们中学学习的知识终于有了用武之地,挽起袖... 查看详情

canvas水波加载动画

  原代码和详细教程请下载附件:链接:https://pan.baidu.com/s/1RwaxZ6DU4EnEtFc4Vck7Uw 提取码:6nha 查看详情

《每周一点canvas动画》——速度与加速度(代码片段)

在上一节中我们介绍了速度的基本概念,包括沿坐标轴的速度,和更普适的任意方向的速度,在文章的最后我们做了一个鼠标跟随的示例,以及通过改变物体的rotation属性做了一个关于速度的扩展。通过上一节的学习你会发现我... 查看详情

html+css+js实现❤️canvas圆形水波进度条动画特效❤️(代码片段)

  🍅作者主页:Java李杨勇 🍅简介:Java领域优质创作者🏆、Java李杨勇公号作者✌ 简历模板、学习资料、面试题库、技术互助【关注我,都给你】🍅欢迎点赞👍收藏⭐留言📝  效果演示&#x... 查看详情

html+css+js实现❤️canvas圆形水波进度条动画特效❤️(代码片段)

  🍅作者主页:Java李杨勇 🍅简介:Java领域优质创作者🏆、Java李杨勇公号作者✌ 简历模板、学习资料、面试题库、技术互助【关注我,都给你】🍅欢迎点赞👍收藏⭐留言📝  效果演示&#x... 查看详情

canvas动画原理与fabric实现

本章节内容主要关注如何在Canvas中绘制动画效果。在HTML5的Canvas中结合JS可以绘制雪碧图动画,动画在一些H5游戏中或者富交互的应用中被广泛使用。游戏的动画帧可以在一个单独的图片中保存,然后使用HTML5的Canvas结合JS在特定... 查看详情

如何用html5的canvas制作3d动画效果

HTML5的诞生给web前端界带来了不小轰动,像什么动画旋转、图片滑块、图片轮播等等这些3D特效,也引发了不少朋友想要学习HTML5的好奇心。最近我一直在做canvas动画效果,发现canvas这个东西做动画不是不可以。相对于flash,它太... 查看详情

如何用html5的canvas制作3d动画效果

HTML5的诞生给web前端界带来了不小轰动,像什么动画旋转、图片滑块、图片轮播等等这些3D特效,也引发了不少朋友想要学习HTML5的好奇心。最近我一直在做canvas动画效果,发现canvas这个东西做动画不是不可以。相对于flash,它太... 查看详情

canvas动画原理与fabric实现

本章节内容主要关注如何在Canvas中绘制动画效果。在HTML5的Canvas中结合JS可以绘制雪碧图动画,动画在一些H5游戏中或者富交互的应用中被广泛使用。游戏的动画帧可以在一个单独的图片中保存,然后使用HTML5的Canvas结合JS在特定... 查看详情

贝塞尔曲线与css3动画svg和canvas的应用

...曲线是可以做出很多复杂的效果来的,比如弹跳球的复杂动画效果,首先加速下降,停止,然后弹起时逐渐减速的效果。使用贝塞尔曲线常用的两个网址如下:缓动函数:http://www.xuanfengge.com/easeing/easeing/cubic-bezier:http://cubic-bezie... 查看详情

html5canvas水波纹动画特效

...不仅可以在Canvas画布上绘制各种图形,也可以制作绚丽的动画,比如这次介绍的水波纹动画特效。以前我们也分享过一款基于HTML5WebGL的水波荡漾动画,让人惊叹不已,这次分享的HTML5Canvas水波纹动画同样非常震撼人心。 在线... 查看详情

前端特效demo|值得收藏的6个html5canvas实用案例

 HTML5动画在Canvas上得到了充分的发挥,我们VIP视频也分享过很多相关的动画特效制作视频,这次给大家带来6款超炫酷的HTML5canvas动画的demo,一起来看看吧~ 文内附有时钟效果代码demo下载地址,感兴趣的小伙伴们可以收藏... 查看详情

Open3d - 将多个点云可视化为视频/动画

】Open3d-将多个点云可视化为视频/动画【英文标题】:Open3d-visualizingmultiplepointcloudsasavideo/animation【发布时间】:2020-07-1510:03:25【问题描述】:我使用RGB+深度视频生成了多个点云,并希望将多个点云可视化为视频或动画。目前我... 查看详情

cesiumczml3d模型动画

...esium自定义3dtiles瓦片场景中,添加3d(gltf)模型贴地行走动画,3d(gltf)上面可以有标牌显示模型名字 //starLng(起始点经度),startLat(起始点纬度),endLng(结束点经度),endLat(结束点纬度)*地图坐标转换参考文章https://www.jianshu.com/p/2e... 查看详情

85.css水波背景动画特效(代码片段)

...附赠【搭建教程】。演示视频【前端特效85】CSS水波背景动画特效视频演示地址一:https://www.ixigua.com/6867470951437566478/视频演示地址二:https://www.bilibili.com/video/BV1Lf4y1X7Bm/源码index.html<!DOCTYPEhtml 查看详情

3d动画制作流程

3D动画制作流程 在游戏动画中,清楚每个环节的细节是很重要的,今天卡拉小编与大家分享的是3D动画制作流程。时代在进步,科技在创新,世界各领域已进入数字媒体信息化,数字3D动画逐渐成为科技行业发展中的中心支柱,近... 查看详情