HTML5 Canvas 无原生 glassRefraction 滤镜,需用 getImageData 读取背景像素,依位移贴图计算偏移量,再通过 putImageData 写回模拟折射效果。
glassRefraction 滤镜Canvas 2D 上下文不支持类似 SVG 或 CSS 的声明式滤镜(如 filter: url(#refraction)),也没有内置的玻璃折射效果 API。所谓“HTML5 玻璃折射”,实际是靠手动采样、偏移、混合像素实现的模拟效果,本质是图像处理而非真光学折射。
getImageData + 偏移采样模拟折射核心思路:把背景图绘制到离屏 canvas,再在主 canvas 上对每个目标像素,根据“玻璃表面法线”或简单位移规则,读取背景图中偏移后的像素值。常见做法是用一张位移贴图(displacement map)控制偏移量。
createImageData 和 getImageData 用于读写像素;注意跨域图片需设置 crossOrigin="anonymous"
dx = (r - 128) * 0.5),避免越界访问putImageData 批量写回,逐像素 fillRect 性能极差const bgData = bgCtx.getImageData(0, 0, w, h);
const outData = ctx.createImageData(w, h);
for (let i = 0; i < data.length; i += 4) {
const x = (i/4) % w;
const y = Math.floor((i/4) / w);
const dx = (displaceData.data[i] - 128) * 0.3;
const dy = (displaceData.data[i+1] - 128) * 0.3;
const srcX = Math.max(0, Math.min(w-1, x + dx));
const srcY = Math.max(0, Math.min(h-1, y + dy));
const srcIdx = (srcY * w + srcX) * 4;
outData.data[i] = bgData.data[srcIdx];
outData.data[i+1] = bgData.data[srcIdx+1];
outData.data[i+2] = bgData.data[srcIdx+2];
outData.data[i+3] = 255;
}
Canvas 2D 的像素操作在中等尺寸(如 800×600)上已明显卡顿;真正可交互的玻璃效果(比如随鼠标扭曲的玻璃球)必须用 WebGL,通过 fragment shader 实时计算折射向量。
refract() GLSL 函数THREE.js 可简化:用 MeshStandardMaterial 配合 envMap 模拟反射+折射,但纯折射仍需自定义 shaderWRAP),折射出界时易黑边,需手动做 mod 或 clamp 处理OES_standard_derivatives 扩展是否可用,否则法线微分不准backdrop-filter 快速模拟毛玻璃,但不是折射如果目标只是「玻璃感」而非物理准确的折射,backdrop-filter: blur(8px) 是最轻量方案,但它只模糊背景,不产生位移、色散或焦散效果。
layout.css.backdrop-filter.enabled
opacity 同时使用会触发渲染层叠问题,建议用 rgba() 控制透明度真实折射要算光线路径,Canvas 2D 只能骗眼,WebGL 才算入门。位移贴图的精度、法线生成方式、以及如何避免采样撕裂,这些细节比“怎么做”更决定最终像不像玻璃。