帮我写一个单文件 HTML,用摄像头 + WebGL 实现"手指划过产生水波纹"的交互艺术效果。
打开摄像头作为背景,WebGL shader 实时叠加水波纹物理。手指在镜头前划过的地方
产生涟漪并向外扩散、约 1 秒消失。画面像被一层水包裹,手划过处折射、放大、扭曲
【技术栈】单文件 HTML,JS/GLSL 全内联,CDN 引依赖,无构建工具
- 渲染:Three.js (WebGL2) ShaderMaterial
- 手部追踪:MediaPipe Hands @0.4
【物理模拟:FBO ping-pong 双缓冲跑波动方程】
- 高度场存 HalfFloat 纹理:R=当前帧高度,G=上一帧高度
- 9-tap 各向同性拉普拉斯(正交权重4、对角1、中心-20,再/6),减方形伪影
- 波动方程:H(t+1) = 2·H(t) − H(t-1) + c²·∇²H
- 非线性衰减:小振幅衰减快(表面张力)、大振幅衰减慢(惯性),
用 mix(dampSmall, dampLarge, smoothstep(0, ampThresh, |H|))
- 手指交互用 capsule SDF(点到线段距离):取手指上一帧→当前帧的线段,
- 注入强度随手速 smoothstep(0, moveThresh, 位移):手停几乎不注入、划过才起波
- 折射:用梯度 grad(不归一化)直接驱动 UV 偏移,坡越陡偏移越大
- 透镜:加 Laplacian 曲率项,波峰有放大镜效果
- 色散:RGB 三通道偏移略有差异,产生彩虹边缘
- Schlick Fresnel:掠射角反光更强
- 波深明暗:波峰偏暖亮(1.0,0.92,0.78)、波谷偏冷暗(0.45,0.65,1.0)
- 双瓣高光:sharp specular(pow 90) + broad sheen(pow 5)
- 只在有波处叠加光照(activity mask),静止画面保持清晰
- 背景压暗:无波区乘 bgDark,水波区保持原亮 → 水波更突出
- 可选背景毛玻璃(Poisson 12-tap),为 0 时跳过采样省性能
【手势】MediaPipe Hands,maxNumHands 2、modelComplexity 0
- 取 10 个指尖(拇/食/中/无名/小 × 双手,landmark 4/8/12/16/20)
- 前摄像头自动镜像;landmark→屏幕坐标含 cover 裁剪逆变换 + 镜像;位置指数滤波降抖
- renderer.setPixelRatio(1)(不跟 devicePixelRatio,Retina 屏省一半以上像素)
- 摄像头请求 640×480(降 ML 输入)
- 手势检测节流 ~15fps(performance.now 间隔 66ms,降 ML 推理频率=降发热)
- 背景毛玻璃为 0 时在 shader 里跳过采样
【参数面板:右上角按钮展开,滑块实时调,默认值如下】
波动物理:波速 0.31 / 注入力度 0.06 / 波源粗细(capsule半径) 0.031 / 余波持久(dampLarge) 0.925
渲染:折射强度 0.12 / 透镜放大 0.25 / 色散 0.30 / 波深明暗 0.30 / 锐高光 1.5 /
背景毛玻璃 0.005 / 背景明暗(bgDark) 0.85
内部固定:dampSmall 0.87、ampThresh 0.12、moveThresh 0.006、simResolution 256
- 单 .html 文件,深色玻璃拟态 UI,关键参数集中在顶部 CONFIG 对象、中文注释
- 摄像头需 localhost 或 https,注释写明 python3 -m http.server 启动方式
- 处理三种状态提示:加载中 / 摄像头权限被拒 / 未检测到手