zoukankan      html  css  js  c++  java
  • canvas水波纹效果

    先看效果

    演示效果

    自然界中水波纹效果十分麻烦,我这里只是根据水波纹的几个特性,在理想环境下模拟水波纹的扩散效果。

    这里应用到的属性有:扩散、波动、折射。

    扩散:很好理解,水波纹会从触发原点开始向周围扩散

    波动:水波纹就一直波,在切面上观看,就是一个正弦函数的波形图

    折射:光在不同介质中传播速度不同导致出现折射效果。

    如果在平静条件下,在垂直方向上看水底事物,很正常。

    在波动条件下,因为水的上下波动,导致垂直方向上看到的水底物体,因为波的角度不同,导致水下事物反射的光到人眼的时候,出现一些偏移。

    找出这个偏移的算法就是这个效果的精髓所在。

    看下图:

    基本算法如下:

    1、  根据公式,正弦函数的波形上的某个点的切线角度。
    sople=cos(len)【sople为斜率,len正弦位置距离原点的位置】

    2、  len要根据水波纹的波长除以2π算出一个周期下r的值
    len=r*PI*2/waveLen【waveLen:水波一个周期的长度】
    sople=cos(r*PI*2/waveLen)

    3、  知道斜率,求出切线的倾斜角
    sopleDeg=atan(sople)
    sopleDeg = (sopleDeg+360)%360

    4、  切线的倾斜角区间为0-360度,入射角区间0-90度
    inDeg= sopleDeg%90

    5、  根据公式,入射角的正弦比上折射角的正弦为折射率
    sin(inDeg)/sin(outDeg)=1.3333
    sin(outDeg)=sin(inDeg)/1.3333
    outDeg=asin(sin(inDeg)/1.3333)

    6、  根据如图,偏移角度为入射角减去折射角
    shiftDeg=inDeg-outDeg

    7、  知道偏移角度和水深可以计算出偏移量
    shift=tan(shiftDeg)*depth

    8、  将偏移量分解为X轴偏移和Y轴偏移
    shiftX=cos(deg)*shift
    shiftY=sin(deg)*shift【deg为当前位置和原点位置所成的夹角】

    那么把真实位置的像素赋值给期待位置,处理所有的点,这样就得到的水波纹效果。

    代码如下:

      1 <!doctype html>
      2 <html lang="en">
      3 <head>
      4     <meta http-equiv="Pragma" content="no-cache" />
      5     <meta http-equiv="Cache-Control" content="no-cache" />
      6     <meta http-equiv="Expires" content="0" />
      7     <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
      8     <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no" />
      9 
     10    <meta charset="UTF-8">
     11     <title>Document</title>
     12 </head>
     13 <body bgcolor="#000000">
     14 <canvas id="canvas"></canvas>
     15 <script type="text/javascript">
     16 (function(){
     17 var canvas = document.getElementById("canvas");
     18 canvas.style.position = "absolute" ;
     19 canvas.style.left = 0 ;
     20 canvas.style.top = 0 ;
     21 var cxt = canvas.getContext("2d");
     22 var imgData ;//原始图片信息
     23 var tempImageData ;//临时图片信息
     24 var depth = 40 ;//水深
     25 var waveLen = 30 ;//水波波长
     26 var step = 0 ;//运动步长
     27 var w , h ;//图片宽高
     28 var sin = Math.sin,
     29     cos = Math.cos,
     30     tan = Math.tan,
     31     atan = Math.atan,
     32     asin = Math.asin,
     33     sqrt = Math.sqrt,
     34     abs = Math.abs ,
     35     round = Math.round,
     36     max = Math.max,
     37     min = Math.min,
     38     PI = Math.PI;
     39 
     40 var n = 1.3333 ;//n=sin(a1)/sin(a2)    a2 = asin(sin(a1)/n)
     41 
     42 var p = {x:150.01,y:150.01};//水波圆心
     43 var r,slope,slopeDeg,inDeg,outDeg,shiftDeg,dir,shift,shiftX,shiftY,position,tmpDepth;
     44 var radius = 0 ;
     45 var speed = 2 ;
     46 var radiusWidth = 60 ;
     47 var timerAnimate = 0 ;
     48 var damp = 1;
     49 
     50 document.onmousedown = function(e){
     51     if(timerAnimate)
     52         clearInterval(timerAnimate);
     53     p = {
     54         x:e.pageX + 0.01,
     55         y:e.pageY + 0.01
     56     };
     57     radius = 0 ;
     58     damp = 1 ;
     59     timerAnimate = setInterval(draw,40);
     60 }
     61 function draw(){
     62     var t = new Date;
     63     step += 1;
     64     radius += speed ;
     65     damp -= 0.01;
     66     for(var x = 0 ; x < w ; x ++){
     67         for(var y = 0 ; y < h ; y ++){
     68             var pxObj = getPoint(imgData,x,y);
     69             setPoint(tempImageData,x,y,pxObj);
     70         }
     71     }
     72     cxt.putImageData(tempImageData,0,0);
     73     console.log(new Date - t);
     74     if(damp < 0){
     75         if(timerAnimate)
     76             clearInterval(timerAnimate);
     77         cxt.putImageData(imgData,0,0);
     78     }
     79 }
     80 function getPoint(img,x,y){
     81     r = sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));
     82     if(r < radius){
     83         position = (r + step)/waveLen*PI*2;//当前位置的代表弧度
     84         tmpDepth = sin(position)*waveLen/PI/2;//水波动引起的临时深度变化
     85         slope = cos(position);//斜率
     86         slopeDeg = atan(slope);//斜角
     87         slopeDeg = abs(slopeDeg*PI*2)%90/(PI*2);//入射角保证为0-360
     88         inDeg = slopeDeg;//入射角
     89         outDeg = asin(sin(inDeg)/n);//折射角
     90         shiftDeg = inDeg - outDeg ;//偏移角
     91         shift = (x-p.x)/abs(x-p.x)*tan(shiftDeg)*(depth+tmpDepth)*damp ;//偏移量
     92         deg = atan((y-p.y)/(x-p.x));
     93         shiftX = cos(deg)*shift ;//X偏移量
     94         shiftY = sin(deg)*shift ;//Y偏移量
     95         x = round(max(0,min(w-1,x+shiftX)));
     96         y = round(max(0,min(h-1,y+shiftY)));
     97     }
     98     var i = (y*w + x ) * 4 ;
     99     var pxObj = [];
    100     pxObj[0] = img.data[i];
    101     pxObj[1] = img.data[i+1];
    102     pxObj[2] = img.data[i+2];
    103     return pxObj;
    104 }
    105 function setPoint(img,x,y,obj){
    106     var i = (y*canvas.width + x ) * 4 ;
    107     img.data[i] = obj[0];
    108     img.data[i+1] = obj[1];
    109     img.data[i+2] = obj[2];
    110     img.data[i+3] = 255;
    111 }
    112 
    113 function init(){
    114     var img = new Image();
    115     img.onload = function(){
    116         canvas.width = this.width ;
    117         canvas.height = this.height;
    118         cxt.drawImage(this,0,0,this.width,this.height);
    119         imgData = cxt.getImageData(0,0,this.width,this.height);
    120         tempImageData = cxt.createImageData(imgData);
    121          w = canvas.width ;
    122         h = canvas.height ;
    123         timerAnimate = setInterval(draw,30);
    124    }
    125    img.src = "4.jpg";
    126 }
    127 init();
    128 })()
    129 
    130 </script>
    131 </body>
    132 </html>

    演示地址:http://suohb.com/work/newWater.html

    更多特效,关注我的微信公众号:

  • 相关阅读:
    docker笔记(1)
    解决MySQL8 #1227 – Access denied; you need (at least one of) the SYSTEM_USER privilege(s) for this ...
    nginx if判断&&和||写法
    泡泡后台Couchbase缓存使用经验分享
    ARTS-WEEK-007
    ARTS-WEEK-006
    ARTS-WEEK-005
    ARTS-WEEK-004
    ARTS-WEEK-003
    总结httpclient资源释放和连接复用
  • 原文地址:https://www.cnblogs.com/shb190802/p/7019432.html
Copyright © 2011-2022 走看看