html5滤镜怎样做玻璃折射_html5玻璃折射滤镜法【技巧】

HTML5 Canvas 无原生 glassRefraction 滤镜,需用 getImageData 读取背景像素,依位移贴图计算偏移量,再通过 putImageData 写回模拟折射效果。

HTML5 Canvas 里没有原生 glassRefraction 滤镜

Canvas 2D 上下文不支持类似 SVG 或 CSS 的声明式滤镜(如 filter: url(#refraction)),也没有内置的玻璃折射效果 API。所谓“HTML5 玻璃折射”,实际是靠手动采样、偏移、混合像素实现的模拟效果,本质是图像处理而非真光学折射。

getImageData + 偏移采样模拟折射

核心思路:把背景图绘制到离屏 canvas,再在主 canvas 上对每个目标像素,根据“玻璃表面法线”或简单位移规则,读取背景图中偏移后的像素值。常见做法是用一张位移贴图(displacement map)控制偏移量。

  • createImageDatagetImageData 用于读写像素;注意跨域图片需设置 crossOrigin="anonymous"
  • 偏移量通常取自另一张灰度图的 R/G 通道值,乘以缩放系数(如 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;
    }

WebGL 是更可行的玻璃折射路径

Canvas 2D 的像素操作在中等尺寸(如 800×600)上已明显卡顿;真正可交互的玻璃效果(比如随鼠标扭曲的玻璃球)必须用 WebGL,通过 fragment shader 实时计算折射向量。

  • 需要定义顶点着色器传入 UV 和法线(或用球面坐标生成),片元着色器中用 refract() GLSL 函数
  • 依赖 THREE.js 可简化:用 MeshStandardMaterial 配合 envMap 模拟反射+折射,但纯折射仍需自定义 shader
  • 注意:WebGL 纹理默认不支持重复采样(WRAP),折射出界时易黑边,需手动做 mod 或 clamp 处理
  • 移动端兼容性需检查 OES_standard_derivatives 扩展是否可用,否则法线微分不准

用 CSS backdrop-filter 快速模拟毛玻璃,但不是折射

如果目标只是「玻璃感」而非物理准确的折射,backdrop-filter: blur(8px) 是最轻量方案,但它只模糊背景,不产生位移、色散或焦散效果。

  • 仅适用于元素后方内容为同文档 DOM 的场景;iframe 或跨域内容不生效
  • Safari 和 Chrome 支持较好,Firefox 默认禁用,需用户手动开启 layout.css.backdrop-filter.enabled
  • opacity 同时使用会触发渲染层叠问题,建议用 rgba() 控制透明度
  • 无法响应鼠标位置动态变形——这是和真折射效果最根本的差距

真实折射要算光线路径,Canvas 2D 只能骗眼,WebGL 才算入门。位移贴图的精度、法线生成方式、以及如何避免采样撕裂,这些细节比“怎么做”更决定最终

像不像玻璃。