首页
   /       /   
使用 WebGL 创建粒子波浪效果
10月
24
使用 WebGL 创建粒子波浪效果
作者: 彭Sir    分类: 网页源码     正在检查是否收录...

使用 WebGL 创建粒子波浪效果


在本篇博客中,我们将探讨如何使用 WebGL 技术创建一个炫酷的粒子波浪效果。这个效果在网页背景或其他项目中可以增加动感和视觉吸引力。我们将使用 HTML、CSS 和 JavaScript 来实现这个效果。

在线演示

https://pengsirs.gitee.io/51xk/15/

项目准备

首先,让我们创建一个基本的 HTML 结构,包括一个画布和所需的 CSS 样式。这将作为我们的基础布局。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>51炫酷网-粒子波浪</title>

<style>
html,
body {
  width: 100%;
  height: 100%;
  margin: 0;
  overflow: hidden;
  background: black;
}

canvas {
  position: relative;
  width: 100%;
  height: 100%;
}

* {
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
  -webkit-tap-highlight-color: transparent;
}

footer {
  position: fixed;
  right: 0;
  top: 0;
  left: 0;
  padding: 10px 10px;
  text-align: right;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
  font-size: 14px;
  color: #fff;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a {
  display: inline-block;
  margin-left: 2px;
  padding: 2px 4px;
  color: #343436;
  text-decoration: none;
  background-color: #fcd000;
  border-radius: 4px;
  opacity: 1;
  -webkit-transition: opacity 0.2s;
  transition: opacity 0.2s;
}
a:hover {
  opacity: 0.6;
}
</style>
</head>
<body>

<canvas></canvas>

<script>
// JavaScript 代码将在下文中添加
</script>
</body>
</html>

在上面的代码中,我们创建了一个全屏画布,它将用于绘制粒子波浪效果。我们还添加了一些样式来设置页面的外观。

创建粒子波浪效果

接下来,我们将添加 JavaScript 代码,以使用 WebGL 技术创建粒子波浪效果。在代码中,我们使用了一个名为 starlings 的库来简化 WebGL 编程。以下是 JavaScript 代码:

<script>
!function(n,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):n.starlings=r()}(this,function(){"use strict";return function(n,r,t,o,e,u,i,f){var a=f.onSetup;void 0===a&&(a=null);var v=f.onRepeat;void 0===v&&(v=null);var c=f.modifier;void 0===c&&(c=null);var l=f.perspective;void 0===l&&(l=1);var d=f.pixelRatio;void 0===d&&(d=1);var m=f.triangles;void 0===m&&(m=!1);var s,p,y=r.length,w=function(n,r){var t=s.createShader(n);return s.shaderSource(t,r),s.compileShader(t),t},b=function(){for(var n=0;n<o.length;n+=1){for(var r=s.createBuffer(),e=o[n],u=e.data(0,0).length,i=new Float32Array(t*y*u),f=0;f<t;f+=1)for(var a=e.data(f,t),v=f*y*u,l=0;l<y;l+=1)for(var d=0;d<u;d+=1)null!==c&&e.name===c.attribute?i[v]=c.value(i[v],a,d,l):i[v]=a[d],v+=1;s.bindBuffer(s.ARRAY_BUFFER,r),s.bufferData(s.ARRAY_BUFFER,i,s.STATIC_DRAW);var m=s.getAttribLocation(p,o[n].name);s.enableVertexAttribArray(m),s.vertexAttribPointer(m,u,s.FLOAT,!1,!1,0,0)}},A=function(){e.push({name:"uMVP",type:"mat4"});for(var n=0;n<e.length;n+=1){var r=s.getUniformLocation(p,e[n].name);e[n].location=r}},F={float:function(n,r){return s.uniform1f(n,r)},vec2:function(n,r){return s.uniform2fv(n,r)},vec3:function(n,r){return s.uniform3fv(n,r)},vec4:function(n,r){return s.uniform4fv(n,r)},mat2:function(n,r){return s.uniformMatrix2fv(n,!1,r)},mat3:function(n,r){return s.uniformMatrix3fv(n,!1,r)},mat4:function(n,r){return s.uniformMatrix4fv(n,!1,r)}},g=function(){s.clear(16640),s.useProgram(p),null!==v&&v(s,p,e);for(var n=0;n<e.length;n+=1)F[e[n].type](e[n].location,e[n].value);s.drawArrays(m?s.TRIANGLES:s.POINTS,0,y*t),requestAnimationFrame(g)},h=function(){n.width=n.clientWidth*d,n.height=n.clientHeight*d;var r=s.drawingBufferWidth,t=s.drawingBufferHeight;s.viewport(0,0,r,t),e[e.length-1].value=[l/(r/t),0,0,0,0,l,0,0,0,0,-1,-1,0,0,1,1]};s=n.getContext("webgl"),p=s.createProgram(),s.attachShader(p,w(s.VERTEX_SHADER,u)),s.attachShader(p,w(s.FRAGMENT_SHADER,i)),s.linkProgram(p),A(),h(),b(),null!==a&&a(s),g(),window.addEventListener("resize",h,!1)}});

"use strict";

// Do you like rainbow waves?
var rainbow = false;

// Need more performance?
var HD = true;

var canvas = document.querySelector("canvas");
var background = document.querySelector(".background");
var bar = document.querySelector(".progress");

var initialize = function initialize(vertices) {
  var pixelRatio = HD ? window.devicePixelRatio : 1;
  var rows = HD ? 90 : 90;
  var multiplier = rows * rows;
  var duration = 0.4;
  var geometry = [{ x: 0, y: 0, z: 0 }];
  var pointSize = (HD ? 6 : 2).toFixed(1);

  var step = 0.004;
  var size = 5;
  var attributes = [{
    name: "aPositionStart",
    data: function data(i, total) {
      return [size - (i % rows / rows + 0.5 / rows) * (size * 2), -1, (size - (Math.floor(i / rows) / rows + 0.5 / rows) * size * 2) * -1];
    }
  }, {
    name: "aControlPointOne",
    data: function data(i) {
      return [size - (i % rows / rows + 0.5 / rows) * (size * 2), -0.5 + getRandom(0.2), (size - (Math.floor(i / rows) / rows + 0.5 / rows) * size * 2) * -1];
    }
  }, {
    name: "aControlPointTwo",
    data: function data(i) {
      return [size - (i % rows / rows + 0.5 / rows) * (size * 2), -0.5 + getRandom(0.2), (size - (Math.floor(i / rows) / rows + 0.5 / rows) * size * 2) * -1];
    }
  }, {
    name: "aPositionEnd",
    data: function data(i) {
      return [size - (i % rows / rows + 0.5 / rows) * (size * 2), -1, (size - (Math.floor(i / rows) / rows + 0.5 / rows) * size * 2) * -1];
    }
  }, {
    name: "aOffset",
    data: function data(i) {
      return [i * ((1 - duration) / (multiplier - 1))];
    }
  }, {
    name: "aColor",
    data: function data(i, total) {
      return getHSL(rainbow ? i / total * 1.0 : 0.5 + i / total * 0.4, 0.5, 0.5);
    }
  }];

  var uniforms = [{
    name: "uProgress",
    type: "float",
    value: 0.8
  }];

  var vertexShader = "\n  attribute vec3 aPositionStart;\n  attribute vec3 aControlPointOne;\n  attribute vec3 aControlPointTwo;\n  attribute vec3 aPositionEnd;\n  attribute float aOffset;\n  attribute vec3 aColor;\n\n  uniform float uProgress;\n  uniform mat4 uMVP;\n\n  varying vec3 vColor;\n\n  vec3 bezier4(vec3 a, vec3 b, vec3 c, vec3 d, float t) {\n    return mix(mix(mix(a, b, t), mix(b, c, t), t), mix(mix(b, c, t), mix(c, d, t), t), t);\n  }\n\n  float easeInOutQuint(float t){\n    return t < 0.5 ? 16.0 * t * t * t * t * t : 1.0 + 16.0 * (--t) * t * t * t * t;\n  }\n\n  void main () {\n    float tProgress = easeInOutQuint(min(1.0, max(0.0, (uProgress - aOffset)) / " + duration + "));\n    vec3 newPosition = bezier4(aPositionStart, aControlPointOne, aControlPointTwo, aPositionEnd, tProgress);\n    gl_PointSize = " + pointSize + " + ((newPosition.y + 1.0) * 80.0);\n    gl_Position = uMVP * vec4(newPosition, 1.0);\n    vColor = aColor;\n  }\n";

  var fragmentShader = "\n  precision mediump float;\n\n  varying vec3 vColor;\n\n  void main() {\n     vec2 pc = 2.0 * gl_PointCoord - 1.0;\n     gl_FragColor = vec4(vColor, 1.0 - dot(pc, pc));\n  }\n";

  var onSetup = function onSetup(gl) {
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
    gl.enable(gl.BLEND);
  };

  var onRepeat = function onRepeat() {
    rotateY(uniforms[uniforms.length - 1].value, 0.002);
    if (uniforms[0].value < 0) {
      uniforms[0].value = 1;
    }
    uniforms[0].value -= step;
  };

  // const diff = (a, b) => Math.abs(a - b);

  // const ratio = window.innerWidth / window.innerHeight;
  // const halfWidth = window.innerWidth / 2;
  // const halfHeight = window.innerHeight / 2;
  // window.addEventListener('mousemove', (e) => {
  //   uniforms[0].value = (((e.clientX - halfWidth) / halfWidth) * ratio).toFixed(4);
  //   uniforms[1].value = (((e.clientY - halfHeight) / halfHeight)).toFixed(4) * -1;
  // });

  var options = {
    onSetup: onSetup,
    onRepeat: onRepeat,
    pixelRatio: pixelRatio
  };

  starlings(canvas, geometry, multiplier, attributes, uniforms, vertexShader, fragmentShader, options);
};

var getRandom = function getRandom(value) {
  return Math.random() * value - value / 2;
};

var rotateY = function rotateY(matrix, angle) {
  var sin = Math.sin(angle);
  var cos = Math.cos(angle);
  var clone = JSON.parse(JSON.stringify(matrix));

  matrix[0] = clone[0] * cos - clone[8] * sin;
  matrix[1] = clone[1] * cos - clone[9] * sin;
  matrix[2] = clone[2] * cos - clone[10] * sin;
  matrix[3] = clone[3] * cos - clone[11] * sin;
  matrix[8] = clone[0] * sin + clone[8] * cos;
  matrix[9] = clone[1] * sin + clone[9] * cos;
  matrix[10] = clone[2] * sin + clone[10] * cos;
  matrix[11] = clone[3] * sin + clone[11] * cos;
};

var h2r = function h2r(p, q, t) {
  if (t < 0) t += 1;
  if (t > 1) t -= 1;
  if (t < 1 / 6) return p + (q - p) * 6 * t;
  if (t < 1 / 2) return q;
  if (t < 2 / 3) return p + (q - p) * 6 * (2 / 3 - t);
  return p;
};

var getHSL = function getHSL(h, s, l) {
  h = (h % 1 + 1) % 1;
  s = Math.max(0, Math.min(1, s));
  l = Math.max(0, Math.min(1, l));
  if (s === 0) return [l, l, l];
  var p = l <= 0.5 ? l * (1 + s) : l + s - l * s;
  var q = 2 * l - p;
  return [h2r(q, p, h + 1 / 3), h2r(q, p, h), h2r(q, p, h - 1 / 3)];
};

initialize();</script>

在上面的 JavaScript 代码中,我们使用了 starlings 库,该库简化了 WebGL 编程,以便创建粒子波浪效果。我们定义了一些参数,例如粒子的大小、颜色、动画等,并且设置了一些动画效果。

总结

通过这篇博客文章,我们学习了如何使用 HTML、CSS 和 JavaScript 创建粒子波浪效果。这个效果可以用于网页背景、动画或其他项目中,增加视觉吸引力。你可以根据自己的需求调整参数来获得不同的效果。希望这篇文章对你有所帮助,让你更了解如何使用 WebGL 技术创建炫酷的效果。

责任声明:本页信息由网友自行发布或来源于网络,真实性、合法性由发布人负责,请仔细甄别!本站只为传递信息,我们不做任何双方证明,也不承担任何法律责任。文章内容若侵犯你的权益,请联系本站删除!
转载声明:本文作者 彭Sir,如需转载请保留文章出处!原文链接请自行复制!

评论

Theme By Brief 鄂ICP备19010459号-4

sitemap

首页

分类

友链