【Three.js 实战】结合 MediaPipe 实现 3D 粒子手势互动特效 (附原理解析)--手势控制粒子项目,附源码

1.前言

1本人心血来潮,看着网上那么多,我自己也vibecoding搞了一个,请看视频

【手势控制粒子-哔哩哔哩】 https://b23.tv/nir9AkU

2.项目解析

1. 项目简介与核心亮点

本项目是一个纯前端的单文件 3D 粒子特效页面。用户可以通过电脑摄像头,用手势(张开/握拳)实时控制 3D 粒子的扩散与聚合,并支持多种形态的平滑切换。

核心能力:

  • 多形态 3D 渲染:支持烟花、球体、心形、花朵、土星等粒子形态。

  • GPU 平滑形变:基于 Shader 实现粒子状态间的丝滑插值过渡,无跳变感。

  • AI 手势交互:接入 MediaPipe Hands,实时捕捉手部动作控制粒子。

  • 可视化控制面板:动态调整颜色、数量、大小、Bloom 辉光效果等参数。

2. 技术栈与运行环境

  • 渲染引擎:Three.js(含EffectComposer后处理)

  • 视觉识别:@mediapipe/hands(手部关键点检测)

  • 架构:HTML + 原生 JS (ES Modules),零构建工具

运行提示:由于需要调用摄像头和加载 ES Module,需通过本地 HTTP 服务启动(如使用 Python:python -m http.server 5500),不要直接双击打开 HTML 文件。

3. 核心技术原理解析

3.1 基于 Shader 的粒子渲染与形变

粒子数量庞大,依靠 CPU 计算性能开销极高。本项目巧妙地将动画逻辑转移至 GPU:

  • 双坐标存储:BufferGeometry中为每个粒子存入aFrom(起始位置) 和aTo(目标位置) 两个 Attribute。

  • 顶点着色器插值:传入uMorph(0到1) 进度变量,在 Shader 中使用mix(aFrom, aTo, progress)计算当前坐标,实现形态间的无缝切换。

  • 动态扰动:结合uTime和自定义随机种子aSeed,让粒子产生自然的呼吸感。

3.2 粒子形态生成算法

通过数学公式在三维空间中撒点:

  • 球体 (Sphere):运用黄金角分布算法,生成分布均匀的球面点阵。

  • 心形 (Heart):使用经典二维心形参数方程(结合 sin 和 cos),并附加 z 轴厚度转为 3D 点云。

  • 花朵 (Flower):利用极坐标花瓣函数生成螺旋增长的形态。

3.3 MediaPipe 手势映射逻辑

如何将摄像头的画面变成粒子的控制力?

  1. 获取骨架点:MediaPipe 实时输出手部 21 个关键点 (Landmarks)。

  2. 计算张开度 (Tension):提取手腕到指尖的距离,对比手腕到指关节的距离,综合评判五根手指的伸直状态,得出一个0~1的张开度分数。

  3. 驱动粒子扩散:将张开度映射为 Shader 中的uSpread(扩散倍率) 变量。

    • 张开度< 0.32(握拳):粒子聚合。

    • 张开度> 0.66(张开):粒子全屏扩散。

  4. 防抖处理:引入简单的缓动函数currentSpread += (targetSpread - currentSpread) * 0.1,消除识别抖动造成的画面闪烁。

4. 避坑指南与优化建议

在实际二开或维护该项目时,需要注意以下几点:

  • 中文乱码问题:如果发现页面 UI 显示乱码,通常是文件编码问题。请务必将 HTML 文件使用UTF-8格式重新保存。

  • CDN 依赖风险:页面高度依赖unpkgjsdelivr。生产环境中建议将 Three.js 和 MediaPipe 核心库下载到本地,避免网络波动导致白屏。

  • 性能瓶颈:粒子数量过高或开启 Bloom 后处理会对低端显卡造成压力。建议根据window.devicePixelRatio限制渲染分辨率,MediaPipe 设置中开启maxNumHands: 1(仅识别单手)以节省 CPU 开销。

  • 工程化改造:虽然单文件便于分享,但后期维护成本高。建议拆分为renderer.js(ThreeJS逻辑)、gestures.js(手势逻辑)、shaders/(着色器文件) 等模块,引入 Vite 或 Webpack 进行管理。

总结:通过这个项目,我们可以清晰地看到Three.js(视觉表现) 与MediaPipe(交互输入) 结合的巨大潜力。掌握 Shader 动画与 AI 数据的映射逻辑,你就能在 Web 端创造出更多极具沉浸感的创意交互体验。

用的开源的手势ai库,大家拿到代码自己分析下吧,下载链接链接我放 评论区吧