分享一个看起来挺酷眩的canvas做的粒子漩涡

如题。上班摸鱼途中逛B站看到的(笑)

直接上效果和代码

 

--------------------------------------------

以下是代码

  1 <!DOCTYPE html>
  2 <html>
  3 
  4   <head>
  5 
  6     <meta charset="utf-8" />
  7 
  8     <title>首页</title>
  9 
 10 
 11 
 12     <style>
 13 
 14       html,
 15 
 16       body {
 17 
 18         margin: 0px;
 19 
 20         width: 100%;
 21 
 22         height: 100%;
 23 
 24         overflow: hidden;
 25 
 26         background: #000;
 27 
 28       }
 29 
 30 
 31 
 32       #canvas {
 33 
 34         position: absolute;
 35 
 36         width: 100%;
 37 
 38         height: 100%;
 39 
 40       }
 41 
 42     </style>
 43 
 44   </head>
 45 
 46   <body>
 47 
 48     <canvas id="canvas"></canvas>
 49 
 50 
 51 
 52     <script>
 53 
 54       function project3D(x, y, z, vars) {
 55 
 56         var p, d;
 57 
 58         x -= vars.camX;
 59 
 60         y -= vars.camY - 8;
 61 
 62         z -= vars.camZ;
 63 
 64         p = Math.atan2(x, z);
 65 
 66         d = Math.sqrt(x * x + z * z);
 67 
 68         x = Math.sin(p - vars.yaw) * d;
 69 
 70         z = Math.cos(p - vars.yaw) * d;
 71 
 72         p = Math.atan2(y, z);
 73 
 74         d = Math.sqrt(y * y + z * z);
 75 
 76         y = Math.sin(p - vars.pitch) * d;
 77 
 78         z = Math.cos(p - vars.pitch) * d;
 79 
 80         var rx1 = -1000;
 81 
 82         var ry1 = 1;
 83 
 84         var rx2 = 1000;
 85 
 86         var ry2 = 1;
 87 
 88         var rx3 = 0;
 89 
 90         var ry3 = 0;
 91 
 92         var rx4 = x;
 93 
 94         var ry4 = z;
 95 
 96         var uc = (ry4 - ry3) * (rx2 - rx1) - (rx4 - rx3) * (ry2 - ry1);
 97 
 98         var ua = ((rx4 - rx3) * (ry1 - ry3) - (ry4 - ry3) * (rx1 - rx3)) / uc;
 99 
100         var ub = ((rx2 - rx1) * (ry1 - ry3) - (ry2 - ry1) * (rx1 - rx3)) / uc;
101 
102         if (!z) z = 0.000000001;
103 
104         if (ua > 0 && ua < 1 && ub > 0 && ub < 1) {
105 
106           return {
107 
108             x: vars.cx + (rx1 + ua * (rx2 - rx1)) * vars.scale,
109 
110             y: vars.cy + (y / z) * vars.scale,
111 
112             d: x * x + y * y + z * z,
113 
114           };
115 
116         } else {
117 
118           return { d: -1 };
119 
120         }
121 
122       }
123 
124 
125 
126       function elevation(x, y, z) {
127 
128         var dist = Math.sqrt(x * x + y * y + z * z);
129 
130         if (dist && z / dist >= -1 && z / dist <= 1) return Math.acos(z / dist);
131 
132         return 0.00000001;
133 
134       }
135 
136 
137 
138       function rgb(col) {
139 
140         col += 0.000001;
141 
142         var r = parseInt((0.5 + Math.sin(col) * 0.5) * 16);
143 
144         var g = parseInt((0.5 + Math.cos(col) * 0.5) * 16);
145 
146         var b = parseInt((0.5 - Math.sin(col) * 0.5) * 16);
147 
148         return "#" + r.toString(16) + g.toString(16) + b.toString(16);
149 
150       }
151 
152 
153 
154       function interpolateColors(RGB1, RGB2, degree) {
155 
156         var w2 = degree;
157 
158         var w1 = 1 - w2;
159 
160         return [
161 
162           w1 * RGB1[0] + w2 * RGB2[0],
163 
164           w1 * RGB1[1] + w2 * RGB2[1],
165 
166           w1 * RGB1[2] + w2 * RGB2[2],
167 
168         ];
169 
170       }
171 
172 
173 
174       function rgbArray(col) {
175 
176         col += 0.000001;
177 
178         var r = parseInt((0.5 + Math.sin(col) * 0.5) * 256);
179 
180         var g = parseInt((0.5 + Math.cos(col) * 0.5) * 256);
181 
182         var b = parseInt((0.5 - Math.sin(col) * 0.5) * 256);
183 
184         return [r, g, b];
185 
186       }
187 
188 
189 
190       function colorString(arr) {
191 
192         var r = parseInt(arr[0]);
193 
194         var g = parseInt(arr[1]);
195 
196         var b = parseInt(arr[2]);
197 
198         return (
199 
200           "#" +
201 
202           ("0" + r.toString(16)).slice(-2) +
203 
204           ("0" + g.toString(16)).slice(-2) +
205 
206           ("0" + b.toString(16)).slice(-2)
207 
208         );
209 
210       }
211 
212 
213 
214       function process(vars) {
215 
216         if (vars.points.length < vars.initParticles)
217 
218           for (var i = 0; i < 5; ++i) spawnParticle(vars);
219 
220         var p, d, t;
221 
222 
223 
224         p = Math.atan2(vars.camX, vars.camZ);
225 
226         d = Math.sqrt(vars.camX * vars.camX + vars.camZ * vars.camZ);
227 
228         d -= Math.sin(vars.frameNo / 80) / 25;
229 
230         t = Math.cos(vars.frameNo / 300) / 165;
231 
232         vars.camX = Math.sin(p + t) * d;
233 
234         vars.camZ = Math.cos(p + t) * d;
235 
236         vars.camY = -Math.sin(vars.frameNo / 220) * 15;
237 
238         vars.yaw = Math.PI + p + t;
239 
240         vars.pitch = elevation(vars.camX, vars.camZ, vars.camY) - Math.PI / 2;
241 
242 
243 
244         var t;
245 
246         for (var i = 0; i < vars.points.length; ++i) {
247 
248           x = vars.points[i].x;
249 
250           y = vars.points[i].y;
251 
252           z = vars.points[i].z;
253 
254           d = Math.sqrt(x * x + z * z) / 1.0075;
255 
256           t = 0.1 / (1 + (d * d) / 5);
257 
258           p = Math.atan2(x, z) + t;
259 
260           vars.points[i].x = Math.sin(p) * d;
261 
262           vars.points[i].z = Math.cos(p) * d;
263 
264           vars.points[i].y +=
265 
266             vars.points[i].vy *
267 
268             t *
269 
270             ((Math.sqrt(vars.distributionRadius) - d) * 2);
271 
272           if (vars.points[i].y > vars.vortexHeight / 2 || d < 0.25) {
273 
274             vars.points.splice(i, 1);
275 
276             spawnParticle(vars);
277 
278           }
279 
280         }
281 
282       }
283 
284 
285 
286       function drawFloor(vars) {
287 
288         var x, y, z, d, point, a;
289 
290         for (var i = -25; i <= 25; i += 1) {
291 
292           for (var j = -25; j <= 25; j += 1) {
293 
294             x = i * 2;
295 
296             z = j * 2;
297 
298             y = vars.floor;
299 
300             d = Math.sqrt(x * x + z * z);
301 
302             point = project3D(x, y - (d * d) / 85, z, vars);
303 
304             if (point.d != -1) {
305 
306               size = 1 + 15000 / (1 + point.d);
307 
308               a = 0.15 - Math.pow(d / 50, 4) * 0.15;
309 
310               if (a > 0) {
311 
312                 vars.ctx.fillStyle = colorString(
313 
314                   interpolateColors(
315 
316                     rgbArray(d / 26 - vars.frameNo / 40),
317 
318                     [0, 128, 32],
319 
320                     0.5 + Math.sin(d / 6 - vars.frameNo / 8) / 2
321 
322                   )
323 
324                 );
325 
326                 vars.ctx.globalAlpha = a;
327 
328                 vars.ctx.fillRect(
329 
330                   point.x - size / 2,
331 
332                   point.y - size / 2,
333 
334                   size,
335 
336                   size
337 
338                 );
339 
340               }
341 
342             }
343 
344           }
345 
346         }
347 
348         vars.ctx.fillStyle = "#82f";
349 
350         for (var i = -25; i <= 25; i += 1) {
351 
352           for (var j = -25; j <= 25; j += 1) {
353 
354             x = i * 2;
355 
356             z = j * 2;
357 
358             y = -vars.floor;
359 
360             d = Math.sqrt(x * x + z * z);
361 
362             point = project3D(x, y + (d * d) / 85, z, vars);
363 
364             if (point.d != -1) {
365 
366               size = 1 + 15000 / (1 + point.d);
367 
368               a = 0.15 - Math.pow(d / 50, 4) * 0.15;
369 
370               if (a > 0) {
371 
372                 vars.ctx.fillStyle = colorString(
373 
374                   interpolateColors(
375 
376                     rgbArray(-d / 26 - vars.frameNo / 40),
377 
378                     [32, 0, 128],
379 
380                     0.5 + Math.sin(-d / 6 - vars.frameNo / 8) / 2
381 
382                   )
383 
384                 );
385 
386                 vars.ctx.globalAlpha = a;
387 
388                 vars.ctx.fillRect(
389 
390                   point.x - size / 2,
391 
392                   point.y - size / 2,
393 
394                   size,
395 
396                   size
397 
398                 );
399 
400               }
401 
402             }
403 
404           }
405 
406         }
407 
408       }
409 
410 
411 
412       function sortFunction(a, b) {
413 
414         return b.dist - a.dist;
415 
416       }
417 
418 
419 
420       function draw(vars) {
421 
422         vars.ctx.globalAlpha = 0.15;
423 
424         vars.ctx.fillStyle = "#000";
425 
426         vars.ctx.fillRect(0, 0, canvas.width, canvas.height);
427 
428 
429 
430         drawFloor(vars);
431 
432 
433 
434         var point, x, y, z, a;
435 
436         for (var i = 0; i < vars.points.length; ++i) {
437 
438           x = vars.points[i].x;
439 
440           y = vars.points[i].y;
441 
442           z = vars.points[i].z;
443 
444           point = project3D(x, y, z, vars);
445 
446           if (point.d != -1) {
447 
448             vars.points[i].dist = point.d;
449 
450             size = 1 + vars.points[i].radius / (1 + point.d);
451 
452             d = Math.abs(vars.points[i].y);
453 
454             a = 0.8 - Math.pow(d / (vars.vortexHeight / 2), 1000) * 0.8;
455 
456             vars.ctx.globalAlpha = a >= 0 && a <= 1 ? a : 0;
457 
458             vars.ctx.fillStyle = rgb(vars.points[i].color);
459 
460             if (
461 
462               point.x > -1 &&
463 
464               point.x < vars.canvas.width &&
465 
466               point.y > -1 &&
467 
468               point.y < vars.canvas.height
469 
470             )
471 
472               vars.ctx.fillRect(
473 
474                 point.x - size / 2,
475 
476                 point.y - size / 2,
477 
478                 size,
479 
480                 size
481 
482               );
483 
484           }
485 
486         }
487 
488         vars.points.sort(sortFunction);
489 
490       }
491 
492 
493 
494       function spawnParticle(vars) {
495 
496         var p, ls;
497 
498         pt = {};
499 
500         p = Math.PI * 2 * Math.random();
501 
502         ls = Math.sqrt(Math.random() * vars.distributionRadius);
503 
504         pt.x = Math.sin(p) * ls;
505 
506         pt.y = -vars.vortexHeight / 2;
507 
508         pt.vy = vars.initV / 20 + Math.random() * vars.initV;
509 
510         pt.z = Math.cos(p) * ls;
511 
512         pt.radius = 200 + 800 * Math.random();
513 
514         pt.color = pt.radius / 1000 + vars.frameNo / 250;
515 
516         vars.points.push(pt);
517 
518       }
519 
520 
521 
522       function frame(vars) {
523 
524         if (vars === undefined) {
525 
526           var vars = {};
527 
528           vars.canvas = document.querySelector("canvas");
529 
530           vars.ctx = vars.canvas.getContext("2d");
531 
532           vars.canvas.width = document.body.clientWidth;
533 
534           vars.canvas.height = document.body.clientHeight;
535 
536           window.addEventListener(
537 
538             "resize",
539 
540             function () {
541 
542               vars.canvas.width = document.body.clientWidth;
543 
544               vars.canvas.height = document.body.clientHeight;
545 
546               vars.cx = vars.canvas.width / 2;
547 
548               vars.cy = vars.canvas.height / 2;
549 
550             },
551 
552             true
553 
554           );
555 
556           vars.frameNo = 0;
557 
558 
559 
560           vars.camX = 0;
561 
562           vars.camY = 0;
563 
564           vars.camZ = -14;
565 
566           vars.pitch = elevation(vars.camX, vars.camZ, vars.camY) - Math.PI / 2;
567 
568           vars.yaw = 0;
569 
570           vars.cx = vars.canvas.width / 2;
571 
572           vars.cy = vars.canvas.height / 2;
573 
574           vars.bounding = 10;
575 
576           vars.scale = 500;
577 
578           vars.floor = 26.5;
579 
580 
581 
582           vars.points = [];
583 
584           vars.initParticles = 700;
585 
586           vars.initV = 0.01;
587 
588           vars.distributionRadius = 800;
589 
590           vars.vortexHeight = 25;
591 
592         }
593 
594 
595 
596         vars.frameNo++;
597 
598         requestAnimationFrame(function () {
599 
600           frame(vars);
601 
602         });
603 
604 
605 
606         process(vars);
607 
608         draw(vars);
609 
610       }
611 
612       frame();
613 
614     </script>
615 
616 
617 
618     <div
619 
620       style="
621 
622         text-align: center;
623 
624         margin: 50px 0;
625 
626         font: normal 14px/24px 'MicroSoft YaHei';
627 
628       "
629 
630     >
631 
632       <p>
633 
634         适用浏览器:360、FireFox、Chrome、Opera、傲游、搜狗、世界之窗.
635 
636         不支持Safari、IE8及以下浏览器。
637 
638       </p>
639 
640       <p>来源:<a href="https://www.cnblogs.com/aixuexi666888/" target="_blank">学习小花</a></p>
641 
642     </div>
643 
644   </body>
645 </html>

 

  

 

        

posted @ 2021-10-24 21:30  aixuexi666888  阅读(139)  评论(0编辑  收藏  举报