webgl+canvas实现炫酷柔和多彩背景动画效果代码
代码语言:html
所属分类:动画
代码描述:webgl+canvas实现炫酷柔和多彩背景动画效果代码
代码标签: webgl canvas 炫酷 柔和 多彩 背景 动画
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <style> * { margin: 0; padding: 0; } body { height: 100vh; width: 100%; display: grid; place-items: stretch; } #gradient-canvas { height: 100vh; width: 100%; background: lightgrey; } </style> </head> <body> <!-- partial:index.partial.html --> <canvas style="--gradient-color-1:#ef008f;--gradient-color-2:#6ec3f4;--gradient-color-3:#7038ff;--gradient-color-4:#e2e2e2;" id="gradient-canvas" data-transition-in></canvas> <script> window.addEventListener('DOMContentLoaded', (e) => { var gradient = new Gradient; gradient.initGradient("#gradient-canvas"); }); </script> <!-- partial --> <script> // https://kevinhufnagl.com/wp-content/themes/lightisol/dist/js/min/lightisol-gradient.min.js?ver=1.0 // function normalizeColor(hexCode) { return [ ((hexCode >> 16) & 255) / 255, ((hexCode >> 8) & 255) / 255, (255 & hexCode) / 255 ]; } ["SCREEN", "LINEAR_LIGHT"].reduce( (hexCode, t, n) => Object.assign(hexCode, { [t]: n }), {} ); class MiniGl { constructor(canvas, width, height, debug = !1) { const _miniGl = this, debug_output = -1 !== document.location.search.toLowerCase().indexOf("debug=webgl"); (_miniGl.canvas = canvas), (_miniGl.gl = _miniGl.canvas.getContext("webgl", { antialias: !0 })), (_miniGl.meshes = []); const context = _miniGl.gl; width && height && this.setSize(width, height), _miniGl.lastDebugMsg, (_miniGl.debug = debug && debug_output ? function (e) { const t = new Date(); t - _miniGl.lastDebugMsg > 1e3 && console.log("---"), console.log( t.toLocaleTimeString() + Array(Math.max(0, 32 - e.length)).join(" ") + e + ": ", ...Array.from(arguments).slice(1) ), (_miniGl.lastDebugMsg = t); } : () => {}), Object.defineProperties(_miniGl, { Material: { enumerable: !1, value: class { constructor(vertexShaders, fragments, uniforms = {}) { const material = this; function getShaderByType(type, source) { const shader = context.createShader(type); return ( context.shaderSource(shader, source), context.compileShader(shader), context.getShaderParameter(shader, context.COMPILE_STATUS) || console.error(context.getShaderInfoLog(shader)), _miniGl.debug("Material.compileShaderSource", { source: source }), shader ); } function getUniformVariableDeclarations(uniforms, type) { return Object.entries(uniforms) .map(([uniform, value]) => value.getDeclaration(uniform, type)) .join("\n"); } (this.uniforms = uniforms), (this.uniformInstances = []); const prefix = "\n precision highp float;\n "; (this.vertexSource = `\n ${prefix}\n attribute vec4 position;\n attribute vec2 uv;\n attribute vec2 uvNorm;\n ${getUniformVariableDeclarations( _miniGl.commonUniforms, "vertex" )}\n ${getUniformVariableDeclarations( uniforms, "vertex" )}\n ${vertexShaders}\n `), (this.Source = `\n ${prefix}\n ${getUniformVariableDeclarations( _miniGl.commonUniforms, "fragment" )}\n ${getUniformVariableDeclarations( uniforms, "fragment" )}\n ${fragments}\n `), (this.vertexShader = getShaderByType( context.VERTEX_SHADER, this.vertexSource )), (this.fragmentShader = getShaderByType( context.FRAGMENT_SHADER, this.Source )), (this.program = context.createProgram()), context.attachShader(this.program, this.vertexShader), context.attachShader(this.program, this.fragmentShader), context.linkProgram(this.program), context.getProgramParameter(this.program, context.LINK_STATUS) || console.error(context.getProgramInfoLog(this.program)), context.useProgram(this.program), this.attachUniforms(void 0, _miniGl.commonUniforms), this.attachUniforms(void 0, this.uniforms); } attachUniforms(name, uniforms) { const material = this; void 0 === name ? Object.entries(uniforms).forEach(([name, uniform]) => { material.attachUniforms(name, uniform); }) : "array" == uniforms.type ? uniforms.value.forEach((uniform, i) => material.attachUniforms(`${name}[${i}]`, uniform) ) : "struct" == uniforms.type ? Object.entries(uniforms.value).forEach(([uniform, i]) => material.attachUniforms(`${name}.${uniform}`, i) ) : (_miniGl.debug("Material.attachUniforms", { name: name, uniform: uniforms }), material.uniformInstances.push({ uniform: uniforms, location: context.getUniformLocation(material.program, name) })); } } }, Uniform: { enumerable: !1, value: class { constructor(e) { (this.type = "float"), Object.assign(this, e), (this.typeFn = { float: "1f", int: "1i", vec2: "2fv", vec3: "3fv", vec4: "4fv", mat4: "Matrix4fv" }[this.type] || "1f"), this.update(); } update(value) { void 0 !== this.value && context[`uniform${this.typeFn}`]( value, 0 === this.typeFn.indexOf("Matrix") ? this.transpose : this.value, 0 === this.typeFn.indexOf("Matrix") ? this.value : null ); } getDeclaration(name, type, length) { const uniform = this; if (uniform.excludeFrom !== type) { if ("array" === uniform.type) return ( uniform.value[0].getDeclaration(name, type, uniform.value.length) + `\nconst int ${name}_length = ${uniform.value.length};` ); if ("struct" === uniform.type) { let name_no_prefix = name.replace("u_", ""); return ( (name_no_prefix = name_no_prefix.charAt(0).toUpperCase() + name_no_prefix.slice(1)), `uniform struct ${name_no_prefix} \n {\n` + Object.entries(uniform.value) .map(([name, uniform]) => uniform.getDeclaration(name, type).replace(/^uniform/, "") ) .join("") + `\n} ${name}${length > 0 ? `[${length}]` : ""};` ); } return `uniform ${uniform.type} ${name}${ length > 0 ? `[${length}]` : "" };`; } } } }, PlaneGeometry: { enumerable: !1, value: class { constructor(width, height, n, i, orientation) { context.createBuffer(), (this.attributes = { position: new _miniGl.Attribute({ target: context.ARRAY_BUFFER, size: 3 }), uv: new _miniGl.Attribute({ target: context.ARRAY_BUFFER, size: 2 }), uvNorm: new _miniGl.Attribute({ target: context.ARRAY_BUFFER, size: 2 }), index: new _miniGl.Attribute({ target: context.ELEMENT_ARRAY_BUFFER, size: 3, type: context.UNSIGNED_SHORT }) }), this.setTopology(n, i), this.setSize(width, height, orientation); } setTopology(e = 1, t = 1) { const n = this; (n.xSegCount = e), (n.ySegCount = t), (n.vertexCount = (n.xSegCount + 1) * (n.ySegCount + 1)), (n.quadCount = n.xSegCount * n.ySegCount * 2), (n.attributes.uv.values = new Float32Array(2 * n.vertexCount)), (n.attributes.uvNorm.values = new Float32Array(2 * n.vertexCount)), (n.attributes.index.values = new Uint16Array(3 * n.quadCount)); for (let e = 0; e <= n.ySegCount; e++) for (let t = 0; t <= n.xSegCount; t++) { const i = e * (n.xSegCount + 1) + t; if ( ((n.attributes.uv.values[2 * i] = t / n.xSegCount), (n.attributes.uv.values[2 * i + 1] = 1 - e / n.ySegCount), (n.attributes.uvNorm.values[2 * i] = (t / n.xSegCount) * 2 - 1), (n.attributes.uvNorm.values[2 * i + 1] = 1 - (e / n.ySegCount) * 2), t < n.xSegCount && e < n.ySegCount) ) { const s = e * n.xSegCount + t; (n.attributes.index.values[6 * s] = i), (n.attributes.index.values[6 * s + 1] = i + 1 + n.xSegCount), (n.attributes.index.values[6 * s + 2] = i + 1), (n.attributes.index.values[6 * s + 3] = i + 1), (n.attributes.index.values[6 * s + 4] = i + 1 + n.xSegCount), (n.attributes.index.values[6 * s + 5] = i + 2 + n.xSegCount); } } n.attributes.uv.update(), n.attributes.uvNorm.update(), n.attributes.index.update(), _miniGl.debug("Geometry.setTopology", { uv: n.attributes.uv, uvNorm: n.attributes.uvNorm, index: n.attributes.index }); } setSize(width = 1, height = 1, orientation = "xz") { const geometry = this; (geometry.width = width), (geometry.height = height), (geometry.orientation = orientation), (geometry.attributes.position.values && geometry.attributes.position.values.length === 3 * geometry.vertexCount) || (geometry.attributes.position.values = new Float32Array( 3 * geometry.vertexCount )); const o = width / -2, r = height / -2, segment_width = width / geometry.xSegCount, segment_height = height / geometry.ySegCount; for (let yIndex = 0; yIndex <= geometry.ySegCount; yIndex++) { const t = r + yIndex * segment_height; for (let xIndex = 0; xIndex <= geometry.xSegCount; xIndex++) { const r = o + xIndex * segment_width, l = yIndex * (geometry.xSegCount + 1) + xIndex; (geometry.attributes.position.values[ 3 * l + "xyz".indexOf(orientation[0]) ] = r), (geometry.attributes.position.values[ 3 * l + "xyz".indexOf(orientation[1]) ] = -t); } } geometry.attributes.position.update(), _miniGl.debug("Geometry.setSize", { position: geometry.attributes.position }); } } }, Mesh: { enumerable: !1, value: class { constructor(geometry, material) { const mesh = this; (mesh.geometry = geometry), (mesh.material = material), (mesh.wireframe = !1), (mesh.attributeInstances = []), Object.entries(mesh.geometry.attributes).forEach(([e, attribute]) => { mesh.attributeInstances.push({ attribute: attribute, location: attribute.attach(e, mesh.material.program) }); }), _miniGl.meshes.push(mesh), _miniGl.debug("Mesh.constructor", { mesh: mesh }); } draw() { context.useProgram(this.material.program), this.material.uniformInstances.forEach(({ uniform: e, location: t }) => e.update(t) ), this.attributeInstances.forEach(({ attribute: e, location: t }) => e.use(t) ), context.drawElements( this.wireframe ? context.LINES : context.TRIANGLES, this.geometry.attributes.index.values.length, context.UNSIGNED_SHORT, 0 ); } remove() { _miniGl.meshes = _miniGl.meshes.filter((e) => e != this); } } }, Attribute: { enumerable: !1, value: class { constructor(e) { (this.type = context.FLOAT), (this.normalized = !1), (this.buffer = context.createBuffer()), Object.assign(this, e), this.update(); } update() { void 0 !== this.values && (context.bindBuffer(this.target, this.buffer), context.bufferData(this.target, this.values, context.STATIC_DRAW)); } attach(e, t) { const n = context.getAttribLocation(t, e); return ( this.target === context.ARRAY_BUFFER && (context.enableVertexAttribArray(n), context.vertexAttribPointer( n, this.size, this.type, this.normalized, 0, 0 )), n ); } use(e) { context.bindBuffer(this.target, this.buffer), this.target === context.ARRAY_BUFFER && (context.enableVertexAttribArray(e), context.vertexAttribPointer( e, this.size, this.type, this.normalized, 0, 0 )); } } } }); const a = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; _miniGl.commonUniforms = { projectionMatrix: new _miniGl.Uniform({ type: "mat4", value: a }), modelViewMatrix: new _miniGl.Uniform({ type: "mat4", value: a }), resolution: new _miniGl.Uniform({ type: "vec2", value: [1, 1] }), aspectRatio: new _miniGl.Uniform({ type: "float", value: 1 }) }; } setSize(e = 640, t = 480) { (this.width = e), (this.height = t), (this.canvas.width = e), (this.canvas.height = t), this.gl.viewport(0, 0, e, t), (this.commonUniforms.resolution.value = [e, t]), (this.commonUniforms.aspectRatio.value = e / t), this.debug("MiniGL.setSize", { width: e, height: t }); } setOrthographicCamera(e = 0, t = 0, n = 0, i = -2e3, s = 2e3) { (this.commonUniforms.projectionMatrix.value = [ 2 / this.width, 0, 0, 0, 0, 2 / this.height, 0, 0, 0, 0, 2 / (i - s), 0, e, t, n, 1 ]), this.debug( "setOrthographicCamera", this.commonUniforms.projectionMatrix.value ); } render() { this.gl.clearColor(0, 0, 0, 0), this.gl.clearDepth(1), this.meshes.forEach((e) => e.draw()); } } function e(object, propertyName, val) { return ( propertyName in object ? Object.defineProperty(object, propertyName, { value: val, enumerable: !0, configurable: !0, writable: !0 }) : (object[propertyName] = val), object ); } class Gradient { constructor(...t) { e(this, "el", void 0), e(this, "cssVarRetries", 0), e(this, "maxCssVarRetries", 200), e(this, "angle", 0), e(this, "isLoadedClass", !1), e(this, "isScrolling", !1), e(this, "scrollingTimeout", void 0), e(this, "scrollingRefreshDelay", 200), e(this, "isIntersecting", !1), e(this, "shaderFiles", void 0), e(this, "vertexShader", void 0), e(this, "sectionColors", void 0), e(this, "computedCanvasStyle", void 0), e(this, "conf", void 0), e(this, "uniforms", void 0), e(this, "t", 1253106), e(this, "last", 0), e(this, "width", void 0), e(this, "minWidth", 1111), e(this, "height", 600), e(this, "xSegCount", void 0), e(this, "ySegCount", void 0), e(this, "mesh", void 0), e(this, "material", void 0), e(this, "geometry", void 0), e(this, "minigl", void 0), e(this, "scrollObserver", void 0), e(this, "amp", 320), e(this, "seed", 5), e(this, "freqX", 14e-5), e(this, "freqY", 29e-5), e(this, "freqDelta", 1e-5), e(this, "activeColors", [1, 1, 1, 1]), e(this, "isMetaKey", !1), e(this, "isGradientLegendVisible", !1), e(this, "isMouseDown", !1), e(this, "handleScroll", () => { clearTimeout(this.scrollingTimeout), (this.scrollingTimeout = setTimeout( this.handleScrollEnd, this.scrollingRefreshDelay )), this.isGradientLegendVisible && this.hideGradientLegend(), this.conf.playing && ((this.isScrolling = !0), this.pause()); }), e(this, "handleScrollEnd", () => { (this.isScrolling = !1), this.isIntersecting && this.play(); }), e(this, "resize", () => { (this.wi.........完整代码请登录后点击上方下载按钮下载查看
网友评论0