以下为核心的 HTML 代码,可以直接复制粘贴到网站的 HTML 文件中 我对 HTML 并不是非常熟悉,所以很可能有更好的实现方式,欢迎大家指正
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebGL Example</title>
<style>
body, html {
margin: 0;
padding: 0;
overflow: hidden;
}
#webgl-container {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
}
#webgl-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="webgl-container">
<canvas id="webgl-canvas"></canvas>
</div>
<script>
// 初始化WebGL上下文
const canvas = document.getElementById('webgl-canvas');
const gl = canvas.getContext('webgl');
// 设置画布大小为全屏
function resizeCanvas() {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
gl.viewport(0, 0, canvas.width, canvas.height);
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
// 顶点着色器代码
const vertexShaderSource = `
attribute vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
`;
// 片元着色器代码
const fragmentShaderSource = `
precision highp float;
uniform float theme;
uniform vec3 w_colour1;
uniform vec3 w_colour2;
uniform vec3 w_colour3;
uniform vec3 w_colour4;
uniform vec3 b_colour1;
uniform vec3 b_colour2;
uniform vec3 b_colour3;
uniform vec3 b_colour4;
uniform int contrast;
uniform float gradual;
uniform float width1;
uniform float width2;
uniform float scale1;
uniform float scale2;
uniform vec2 offset;
uniform float intensity;
uniform float spin_speed;
uniform float spin_amount;
uniform float time;
uniform float canvas_width; // 新增画布宽度uniform变量
uniform float canvas_height; // 新增画布高度uniform变量
void main() {
vec3 colour1 = mix(w_colour1, b_colour1, theme);
vec3 colour2 = mix(w_colour2, b_colour2, theme);
vec3 colour3 = mix(w_colour3, b_colour3, theme);
vec3 colour4 = mix(w_colour4, b_colour4, theme);
float speed = time * spin_speed;
// 无拉伸屏幕 UV;
vec2 uv = gl_FragCoord.xy / canvas_height;
// 居中 UV
float center = canvas_width / canvas_height;
uv.y -= 0.5;
uv.x -= 0.5 * center;
uv *= 2.0;
uv += offset;
float uv_len = length(uv);
// 获得角度信息
float angle = atan(uv.y, uv.x);
// 根据距离衰减旋转
angle -= spin_amount * uv_len;
// 角度旋转动画
angle += speed;
// 根据距离应用旋转
uv = vec2(uv_len * cos(angle), uv_len * sin(angle)) * scale2;
// UV 扭曲效果
uv *= scale1;
vec2 uv2 = vec2(uv.x + uv.y);
for (int i = 0; i < 5; i++) {
uv2 += sin(uv);
uv += vec2(cos(intensity * uv2.y + speed), sin(intensity * uv2.x - speed));
uv -= cos(uv.x + uv.y) - sin(uv.x - uv.y);
}
// 强度值
float paint_res = smoothstep(0.0, gradual, length(uv) / scale1);
// 色块划分
float c3p = 1.0 - min(width2, abs(paint_res - 0.5)) * (1.0 / width2);
float c_out = max(0.0, (paint_res - (1.0 - width1))) * (1.0 / width1);
float c_in = max(0.0, -(paint_res - width1)) * (1.0 / width1);
float c4p = c_out + c_in;
// 颜色应用
vec3 ret_col = mix(colour1, colour2, paint_res);
ret_col = mix(ret_col, colour3, c3p);
ret_col = mix(ret_col, colour4, c4p);
gl_FragColor = vec4(ret_col * mix(uv_len / 2.0, 1.0, theme), 1.0);
// gl_FragColor = vec4(uv.y); // 纯红色
}
`;
// 创建和编译着色器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
// 创建程序对象并链接着色器
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
// 检查链接是否成功
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('Unable to link the shader program: ' + gl.getProgramInfoLog(program));
}
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
console.error('Failed to compile vertex shader: ' + gl.getShaderInfoLog(vertexShader));
}
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
console.error('Failed to compile fragment shader: ' + gl.getShaderInfoLog(fragmentShader));
}
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('Unable to link the shader program: ' + gl.getProgramInfoLog(program));
}
// 使用程序对象
gl.useProgram(program);
// 设置顶点数据
const vertexData = new Float32Array([
-1.0, 1.0, // 第一个顶点
-1.0, -1.0, // 第二个顶点
1.0, -1.0, // 第三个顶点
1.0, 1.0 // 第四个顶点
]);
// 设置变量
const uniformLocations = {
theme: gl.getUniformLocation(program, 'theme'),
w_colour1: gl.getUniformLocation(program, 'w_colour1'),
w_colour2: gl.getUniformLocation(program, 'w_colour2'),
w_colour3: gl.getUniformLocation(program, 'w_colour3'),
w_colour4: gl.getUniformLocation(program, 'w_colour4'),
b_colour1: gl.getUniformLocation(program, 'b_colour1'),
b_colour2: gl.getUniformLocation(program, 'b_colour2'),
b_colour3: gl.getUniformLocation(program, 'b_colour3'),
b_colour4: gl.getUniformLocation(program, 'b_colour4'),
contrast: gl.getUniformLocation(program, 'contrast'),
gradual: gl.getUniformLocation(program, 'gradual'),
width1: gl.getUniformLocation(program, 'width1'),
width2: gl.getUniformLocation(program, 'width2'),
scale1: gl.getUniformLocation(program,'scale1'),
scale2: gl.getUniformLocation(program,'scale2'),
offset: gl.getUniformLocation(program, 'offset'),
intensity: gl.getUniformLocation(program, 'intensity'),
spin_speed: gl.getUniformLocation(program,'spin_speed'),
spin_amount: gl.getUniformLocation(program,'spin_amount'),
time: gl.getUniformLocation(program, 'time'),
canvas_width: gl.getUniformLocation(program, 'canvas_width'),
canvas_height: gl.getUniformLocation(program, 'canvas_height')
};
// 设置uniform变量的值
gl.uniform1f(uniformLocations.theme, 0);
gl.uniform3f(uniformLocations.w_colour1, 0.0, 0.427, 0.62);
gl.uniform3f(uniformLocations.w_colour2, 0.0, 0.63, 0.43);
gl.uniform3f(uniformLocations.w_colour3, 1.0, 1.0, 1.0);
gl.uniform3f(uniformLocations.w_colour4, 0.0, 0.0, 0.0);
gl.uniform3f(uniformLocations.b_colour1, 0.0, 0.42, 0.61);
gl.uniform3f(uniformLocations.b_colour2, 0.0, 0.61, 0.57);
gl.uniform3f(uniformLocations.b_colour3, 1.0, 1.0, 1.0);
gl.uniform3f(uniformLocations.b_colour4, 1.0, 1.0, 1.0);
gl.uniform1i(uniformLocations.contrast, 5);
gl.uniform1f(uniformLocations.gradual, 2.0);
gl.uniform1f(uniformLocations.width1, 0.2);
gl.uniform1f(uniformLocations.width2, 0.1);
gl.uniform1f(uniformLocations.scale1, 10.0);
gl.uniform1f(uniformLocations.scale2, 1.0);
gl.uniform2f(uniformLocations.offset, 0.0, 0.0);
gl.uniform1f(uniformLocations.intensity, 0.2);
gl.uniform1f(uniformLocations.spin_speed, 0.2);
gl.uniform1f(uniformLocations.spin_amount, 1.5);
gl.uniform1f(uniformLocations.time, 1.0);
gl.uniform1f(uniformLocations.canvas_width, canvas.width);
gl.uniform1f(uniformLocations.canvas_height, canvas.height);
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW);
const positionAttribLocation = gl.getAttribLocation(program, 'position');
gl.vertexAttribPointer(
positionAttribLocation,
2, // 每个顶点有2个分量(x, y)
gl.FLOAT, // 数据类型是32位浮点数
false,
2 * Float32Array.BYTES_PER_ELEMENT, // 步长
0 // 偏移量
);
gl.enableVertexAttribArray(positionAttribLocation);
var a = 0;
var n_a = 0;
// 同步更新页面主题
window.addEventListener('storage', (event) => {
if (localStorage.getItem('pref-theme') === 'dark') {
a = 0;
} else {
a = 1;
}
});
// 初始化
window.dispatchEvent(new Event('storage'));
// 清除画布并绘制三角形
function render() {
// 实时更新的值
gl.uniform1f(uniformLocations.time, performance.now() / 1000.0);
gl.uniform1f(uniformLocations.canvas_width, canvas.width);
gl.uniform1f(uniformLocations.canvas_height, canvas.height);
if (n_a == a) {
n_a = a;
} else {
n_a = lerpi(n_a, a, 0.4);
}
gl.uniform1f(uniformLocations.theme, n_a);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
requestAnimationFrame(render);
}
render();
// 插值
function lerpi(a, b, t) {
return a + ( b - a ) * t;
}
</script>
</body>
</html>
只需要将以上 HTML 文件插入到页面中
<iframe id="webgl-background" src="/html/WebGL.html" width="100%" height="100%" frameborder="0"></iframe>
再设置一下 CSS 样式即可作为背景使用
<style>
<!-- 头像缩放适配 -->
<!-- 背景/隐藏滚动条 -->
<style>
iframe#webgl-background {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -999;
border: none;
pointer-events: none;
}
</style>