手势控制 3D 圣诞树 —— 2025年的Web互动新玩法

25 年 12 月 17 日 星期三 (已编辑)
1214 字
7 分钟

今年圣诞节来点不一样的。抛弃鼠标点击,用 MediaPipe 和 Three.js 实现一个手势控制的 3D 粒子圣诞树。本文记录了实现思路和核心代码。 🚀

粒子圣诞树预览

🎅 项目简介

Gesture Controlled Christmas Tree 是一个 Web 端的互动 Demo。利用计算机视觉技术实时捕捉手势,控制 3D 场景中的粒子变化。粒子可以汇聚成树,或者炸裂成星云,还可以支持照片悬浮展示。

✨ 核心功能

  • 🌌 粒子系统:基于 Three.js 构建,高性能渲染大量粒子。
  • 🙌 手势交互:利用 MediaPipe 实现无接触控制,无需任何额外硬件。
  • 📸 照片展示:支持自定义上传照片,悬浮在 3D 场景中。
  • 🎶 音频可视化:Web Audio API 解析音乐频率,让视觉元素随音乐律动。
  • 🌏 多语言:支持中英切换。

🎮 交互说明

项目集成了 MediaPipe Tasks Vision 进行手部追踪,预设了三种控制手势:

手势图标功能
握拳 (Fist)✊聚合:将所有粒子和照片汇聚成旋转的圣诞树形态。
张开手掌 (Open)🖐爆发:圣诞树炸裂,切换为星云环绕模式,照片悬浮。
捏合 (Pinch)👌选中:计算空间距离,选中并放大离视角最近的照片。

🤖 识别逻辑

手势识别主要依靠计算关键点之间的欧几里得距离:

javascript
// ✊ 握拳检测:判断指尖到掌心(MCP关节)的距离
const isFingerCurled = (tip, mcp) => {
  const distance = Math.sqrt(Math.pow(tip.x - mcp.x, 2) + Math.pow(tip.y - mcp.y, 2))
  return distance < 0.08 // 阈值,根据实际体验调整
}

// 👌 捏合检测:判断拇指于食指尖距离
const isPinching = (thumb, index) => {
  const distance = Math.sqrt(Math.pow(thumb.x - index.x, 2) + Math.pow(thumb.y - index.y, 2))
  return distance < 0.06
}

为了解决视觉识别抖动的问题(每帧识别结果可能跳变),实现了一个简单的 手势防抖器 (GestureStabilizer),基于滑动窗口算法:

javascript
class GestureStabilizer {
  constructor(windowSize = 8) {
    this.history = [] // 历史帧缓存
    this.windowSize = windowSize
  }

  getStabilizedGesture() {
    // 简单投票机制:窗口内超过 50% 的结果一致才判定为有效切换
    // ... (投票逻辑)
    return maxCount > this.windowSize * 0.5 ? stabilized : lastGesture
  }
}

🛠️ 技术栈

技术用途
Three.js核心 3D 渲染引擎,负责场景、粒子和几何体。
MediaPipeGoogle 的开源机器学习方案,负责前端即时手部追踪。
EffectComposerThree.js 的后期处理库,实现 Bloom 辉光效果。
Web Audio API原生音频 API,用于获取音频频域数据实现可视化。
Vite构建工具,提供极速的开发体验。

🚀 快速开始

环境准备

  • Node.js 18+
  • pnpm / npm
  • 必要硬件:摄像头

运行步骤

bash
# 1. 克隆仓库

cd gesture-christmas-main

# 2. 安装依赖
pnpm install

# 3. 启动开发服
pnpm dev

注意:由于浏览器安全策略,摄像头访问必须在 HTTPS 或 localhost 环境下进行。请勿直接双击打开 html 文件。


⚙️ 配置参数

项目中的 CONFIG 对象集中管理了主要参数,可以在 index.html 中直接调整:

javascript
const CONFIG = {
  // 🌟 粒子设置
  primaryParticleCount: 1200, // 主粒子数
  secondaryParticleCount: 2000, // 背景氛围粒子数

  // 🎄 树形态
  treeHeight: 30,
  treeRadius: 14,

  // ✨ 后期特效
  bloomStrength: 1.2, // 辉光强度
  bloomRadius: 0.5,

  // 🎨 颜色
  colors: [0x2f4f4f, 0x556b2f, 0xb22222, 0xffd700, 0xffffff],

  // 🖼️ 照片展示
  photoTreeScale: 0.15, // 树模式下的照片缩放
  photoHoverScale: 2.0, // 悬停缩放
}

🖼️ 自定义照片

除了默认资源,支持自定义上传:

  1. 界面操作:点击右下角「上传照片」按钮。
  2. 配置文件:将图片放入 images/ 目录,并更新 images/manifest.json:
json
{
  "images": ["my-cat.jpg", "party.png", "love.jpg"]
}

🎨 实现细节

1. 圆锥螺旋分布

粒子树的构建算法使用了圆锥螺旋方程,确保粒子分布均匀且有层次感:

javascript
const angle = (i / count) * Math.PI * 20 // 螺旋角
const y = (i / count) * height - height / 2 // 高度
const r = radius * (1 - (y + height / 2) / height) // 半径随高度收缩

2. Bloom 辉光

使用 Three.js 的 UnrealBloomPass 实现辉光。这是提升 3D 场景质感的关键,能让简单的几何体看起来更有“光感”。

3. 音频可视化

利用 AnalyserNode 获取 FFT 数据,将低频分量映射到树的整体 Scale,高频分量映射到背景粒子的闪烁强度。


📦 部署

bash
pnpm build

构建产物在 dist/ 目录。推荐部署到 Vercel 或 GitHub Pages。


❓ FAQ

  • Q: 无法调用摄像头?
    • A: 检查浏览器权限设置。确保是在 HTTPS 或 localhost 下访问。
  • Q: 手势识别不准?
    • A: 尽量在光线充足的环境下使用。背景不要过于杂乱。
  • Q: 帧率低?
    • A: 计算机视觉+3D渲染对性能有一定要求。如果卡顿,降低 CONFIG.primaryParticleCount 即可。

🙏 致谢


Merry Christmas & Happy Coding! 🎄

文章标题:手势控制 3D 圣诞树 —— 2025年的Web互动新玩法

文章作者:qqyule

文章链接:https://justidea.cn/posts/gesture-controlled-3d-christmas-tree

最后修改时间:


作者签名

商业转载请联系站长获得授权,非商业转载请注明本文出处及文章链接,您可以自由地在任何媒体以任何形式复制和分发作品,也可以修改和创作,但是分发衍生作品时必须采用相同的许可协议。
本文采用CC BY-NC-SA 4.0进行许可。