欢迎加QQ交流:
2
0
2
3

canvas 粒子 炫酷龙卷风-块状

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>粒子漩涡特效</title>
    <style>
      html,body{
        margin:0px;
        width:100%;
        height:100%;
        overflow:hidden;
        background:#000;
      }
      #canvas{
        position:absolute;
        width:100%;
        height:100%;
      }
    </style>
  </head>
  <body>
  <canvas id="canvas"></canvas>
  <script>
    function project3D(x,y,z,vars){
      var p,d;
      x-=vars.camX;
      y-=vars.camY-8;
      z-=vars.camZ;
      p=Math.atan2(x,z);
      d=Math.sqrt(x*x+z*z);
      x=Math.sin(p-vars.yaw)*d;
      z=Math.cos(p-vars.yaw)*d;
      p=Math.atan2(y,z);
      d=Math.sqrt(y*y+z*z);
      y=Math.sin(p-vars.pitch)*d;
      z=Math.cos(p-vars.pitch)*d;
      var rx1=-1000;
      var ry1=1;
      var rx2=1000;
      var ry2=1;
      var rx3=0;
      var ry3=0;
      var rx4=x;
      var ry4=z;
      var uc=(ry4-ry3)*(rx2-rx1)-(rx4-rx3)*(ry2-ry1);
      var ua=((rx4-rx3)*(ry1-ry3)-(ry4-ry3)*(rx1-rx3))/uc;
      var ub=((rx2-rx1)*(ry1-ry3)-(ry2-ry1)*(rx1-rx3))/uc;
      if(!z)z=0.000000001;
      if(ua>0&&ua<1&&ub>0&&ub<1){
        return {
          x:vars.cx+(rx1+ua*(rx2-rx1))*vars.scale,
          y:vars.cy+y/z*vars.scale,
          d:(x*x+y*y+z*z)
          };
      }else{
        return { d:-1 };
      }
    }
    function elevation(x,y,z){
      var dist = Math.sqrt(x*x+y*y+z*z);
      if(dist && z/dist>=-1 && z/dist <=1) return Math.acos(z / dist);
      return 0.00000001;
    }
    function rgb(col){
      col += 0.000001;
      var r = parseInt((0.5+Math.sin(col)*0.5)*16);
      var g = parseInt((0.5+Math.cos(col)*0.5)*16);
      var b = parseInt((0.5-Math.sin(col)*0.5)*16);
      return "#"+r.toString(16)+g.toString(16)+b.toString(16);
    }
    function interpolateColors(RGB1,RGB2,degree){
      var w2=degree;
      var w1=1-w2;
      return [w1*RGB1[0]+w2*RGB2[0],w1*RGB1[1]+w2*RGB2[1],w1*RGB1[2]+w2*RGB2[2]];
    }
    function rgbArray(col){
      col += 0.000001;
      var r = parseInt((0.5+Math.sin(col)*0.5)*256);
      var g = parseInt((0.5+Math.cos(col)*0.5)*256);
      var b = parseInt((0.5-Math.sin(col)*0.5)*256);
      return [r, g, b];
    }
    function colorString(arr){
      var r = parseInt(arr[0]);
      var g = parseInt(arr[1]);
      var b = parseInt(arr[2]);
      return "#"+("0" + r.toString(16) ).slice (-2)+("0" + g.toString(16) ).slice (-2)+("0" + b.toString(16) ).slice (-2);
    }
    function process(vars){
      if(vars.points.length<vars.initParticles) for(var i=0;i<5;++i) spawnParticle(vars);
      var p,d,t;
      p = Math.atan2(vars.camX, vars.camZ);
      d = Math.sqrt(vars.camX * vars.camX + vars.camZ * vars.camZ);
      d -= Math.sin(vars.frameNo / 80) / 25;
      t = Math.cos(vars.frameNo / 300) / 165;
      vars.camX = Math.sin(p + t) * d;
      vars.camZ = Math.cos(p + t) * d;
      vars.camY = -Math.sin(vars.frameNo / 220) * 15;
      vars.yaw = Math.PI + p + t;
      vars.pitch = elevation(vars.camX, vars.camZ, vars.camY) - Math.PI / 2;
      var t;
      for(var i=0;i<vars.points.length;++i){
        x=vars.points[i].x;
        y=vars.points[i].y;
        z=vars.points[i].z;
        d=Math.sqrt(x*x+z*z)/1.0075;
        t=.1/(1+d*d/5);
        p=Math.atan2(x,z)+t;
        vars.points[i].x=Math.sin(p)*d;
        vars.points[i].z=Math.cos(p)*d;
        vars.points[i].y+=vars.points[i].vy*t*((Math.sqrt(vars.distributionRadius)-d)*2);
        if(vars.points[i].y>vars.vortexHeight/2 || d<.25){
          vars.points.splice(i,1);
          spawnParticle(vars);
        }
      }
    }
    function drawFloor(vars){
      var x,y,z,d,point,a;
      for (var i = -25; i <= 25; i += 1) {
        for (var j = -25; j <= 25; j += 1) {
          x = i*2;
          z = j*2;
          y = vars.floor;
          d = Math.sqrt(x * x + z * z);
          point = project3D(x, y-d*d/85, z, vars);
          if (point.d != -1) {
            size = 1 + 15000 / (1 + point.d);
            a = 0.15 - Math.pow(d / 50, 4) * 0.15;
            if (a > 0) {
              vars.ctx.fillStyle = colorString(interpolateColors(rgbArray(d/26-vars.frameNo/40),[0,128,32],.5+Math.sin(d/6-vars.frameNo/8)/2));
              vars.ctx.globalAlpha = a;
              vars.ctx.fillRect(point.x-size/2,point.y-size/2,size,size);
            }
          }
        }
      }
      vars.ctx.fillStyle = "#82f";
      for (var i = -25; i <= 25; i += 1) {
        for (var j = -25; j <= 25; j += 1) {
          x = i*2;
          z = j*2;
          y = -vars.floor;
          d = Math.sqrt(x * x + z * z);
          point = project3D(x, y+d*d/85, z, vars);
          if (point.d != -1) {
            size = 1 + 15000 / (1 + point.d);
            a = 0.15 - Math.pow(d / 50, 4) * 0.15;
            if (a > 0) {
              vars.ctx.fillStyle = colorString(interpolateColors(rgbArray(-d/26-vars.frameNo/40),[32,0,128],.5+Math.sin(-d/6-vars.frameNo/8)/2));
              vars.ctx.globalAlpha = a;
              vars.ctx.fillRect(point.x-size/2,point.y-size/2,size,size);
            }
          }
        }
      }
    }
    function sortFunction(a,b){
      return b.dist-a.dist;
    }
    function draw(vars){
      vars.ctx.globalAlpha=.15;
      vars.ctx.fillStyle="#000";
      vars.ctx.fillRect(0, 0, canvas.width, canvas.height);
      drawFloor(vars);
      var point,x,y,z,a;
      for(var i=0;i<vars.points.length;++i){
        x=vars.points[i].x;
        y=vars.points[i].y;
        z=vars.points[i].z;
        point=project3D(x,y,z,vars);
        if(point.d != -1){
          vars.points[i].dist=point.d;
          size=1+vars.points[i].radius/(1+point.d);
          d=Math.abs(vars.points[i].y);
          a = .8 - Math.pow(d / (vars.vortexHeight/2), 1000) * .8;
          vars.ctx.globalAlpha=a>=0&&a<=1?a:0;
          vars.ctx.fillStyle=rgb(vars.points[i].color);
          if(point.x>-1&&point.x<vars.canvas.width&&point.y>-1&&point.y<vars.canvas.height)vars.ctx.fillRect(point.x-size/2,point.y-size/2,size,size);
        }
      }
      vars.points.sort(sortFunction);
    }
    function spawnParticle(vars){
      var p,ls;
      pt={};
      p=Math.PI*2*Math.random();
      ls=Math.sqrt(Math.random()*vars.distributionRadius);
      pt.x=Math.sin(p)*ls;
      pt.y=-vars.vortexHeight/2;
      pt.vy=vars.initV/20+Math.random()*vars.initV;
      pt.z=Math.cos(p)*ls;
      pt.radius=200+800*Math.random();
      pt.color=pt.radius/1000+vars.frameNo/250;
      vars.points.push(pt);
    }
    function frame(vars) {
      if(vars === undefined){
        var vars={};
        vars.canvas = document.querySelector("canvas");
        vars.ctx = vars.canvas.getContext("2d");
        vars.canvas.width = document.body.clientWidth;
        vars.canvas.height = document.body.clientHeight;
        window.addEventListener("resize", function(){
        vars.canvas.width = document.body.clientWidth;
        vars.canvas.height = document.body.clientHeight;
        vars.cx=vars.canvas.width/2;
        vars.cy=vars.canvas.height/2;
        }, true);
        vars.frameNo=0;
        vars.camX = 0;
        vars.camY = 0;
        vars.camZ = -14;
        vars.pitch = elevation(vars.camX, vars.camZ, vars.camY) - Math.PI / 2;
        vars.yaw = 0;
        vars.cx=vars.canvas.width/2;
        vars.cy=vars.canvas.height/2;
        vars.bounding=10;
        vars.scale=500;
        vars.floor=26.5;
        vars.points=[];
        vars.initParticles=700;
        vars.initV=.01;
        vars.distributionRadius=800;
        vars.vortexHeight=25;
      }
      vars.frameNo++;
      requestAnimationFrame(function() {
        frame(vars);
      });
      process(vars);
      draw(vars);
    }
    frame();
  </script>
  </body>
</html>
posted @ 2021-12-27 15:46  常安·  阅读(28)  评论(0编辑  收藏  举报