分享一个看起来挺酷眩的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>
本文来自学习小花,作者:aixuexi666888,转载请注明原文链接:https://www.cnblogs.com/aixuexi666888/p/15455796.html