1. 项目概述:手势操控的粒子土星
这个项目通过Three.js和MediaPipe技术,实现了一个可以用手势控制的3D粒子土星模型。当用户将手置于摄像头前时,系统能够识别手势动作并实时控制土星模型的旋转、缩放等效果。这个项目完美结合了计算机视觉和Web 3D图形技术,创造了一个极具科技感和互动性的视觉体验。
核心功能包括:
- 手掌移动控制土星旋转(X/Y轴)
- 捏合手势控制土星大小
- "比耶"手势一键复位
- 手部移出画面自动锁定
2. 技术架构解析
2.1 核心技术栈
这个项目主要基于以下技术构建:
- Three.js:用于创建和渲染3D场景的核心库
- MediaPipe Hands:Google提供的实时手部追踪解决方案
- WebGL:底层图形渲染API
- GLSL着色器:自定义粒子效果的核心
2.2 系统架构设计
整个系统采用模块化设计,主要包含以下几个核心模块:
- 手部追踪模块:负责识别和解析手势
- 3D场景模块:管理Three.js场景、相机和渲染器
- 粒子系统模块:生成和渲染土星粒子效果
- 状态管理模块:处理不同交互状态间的转换
- UI界面模块:显示系统状态和操作提示
3. 核心实现细节
3.1 手部追踪实现
MediaPipe Hands的初始化配置:
javascript复制const hands = new Hands({
locateFile: (f) => `https://cdn.jsdelivr.net/npm/@mediapipe/hands/${f}`
});
hands.setOptions({
maxNumHands: 1,
modelComplexity: 1,
minDetectionConfidence: 0.65,
minTrackingConfidence: 0.65
});
手部追踪结果处理逻辑:
javascript复制hands.onResults((results) => {
if (results.multiHandLandmarks?.length > 0) {
const hand = results.multiHandLandmarks[0];
// 手势识别和处理逻辑...
}
});
3.2 粒子土星生成
土星粒子系统由两部分组成:
- 土星本体粒子(25%)
- 土星环粒子(75%)
粒子属性设置代码:
javascript复制for(let i = 0; i < CONFIG.particles; i++) {
if (i < CONFIG.particles * 0.25) {
// 土星本体粒子
const phi = Math.acos(2 * Math.random() - 1);
const theta = 2 * Math.PI * Math.random();
x = R * Math.sin(phi) * Math.cos(theta);
y = R * Math.cos(phi) * 0.9; // 稍微压扁
z = R * Math.sin(phi) * Math.sin(theta);
} else {
// 土星环粒子
const zR = Math.random();
if (zR < 0.15) {
ringR = R * (1.235 + Math.random()*0.29);
}
// 其他环层...
}
}
3.3 手势交互实现
3.3.1 旋转控制
通过手掌中心点(landmark 9)的位置计算旋转角度:
javascript复制const palm = hand[9];
smoothedPalmX += (palm.x - smoothedPalmX) * 0.15;
smoothedPalmY += (palm.y - smoothedPalmY) * 0.15;
targetRotY = -(smoothedPalmX - 0.5) * Math.PI * 2.5;
targetRotX = (smoothedPalmY - 0.5) * Math.PI * 1.5;
3.3.2 缩放控制
通过拇指(landmark 4)和食指(landmark 8)的距离计算缩放比例:
javascript复制const rawPinchDist = Math.hypot(hand[4].x - hand[8].x, hand[4].y - hand[8].y);
smoothedPinchDist += (rawPinchDist - smoothedPinchDist) * 0.15;
targetScale = 0.15 + Math.max(0, Math.min(1, (smoothedPinchDist - 0.02) / 0.18)) * 2.6;
3.3.3 "比耶"手势识别
识别逻辑基于手指关节位置关系:
javascript复制const indexUp = hand[8].y < hand[6].y; // 食指伸直
const middleUp = hand[12].y < hand[10].y; // 中指伸直
const ringDown = hand[16].y > hand[14].y; // 无名指弯曲
const pinkyDown = hand[20].y > hand[18].y; // 小指弯曲
const isVSign = indexUp && middleUp && ringDown && pinkyDown;
4. 高级特性实现
4.1 状态机设计
系统设计了三种状态来管理交互:
- IDLE:待机状态,土星自动缓慢旋转
- TRACKING:追踪状态,响应手势控制
- FROZEN:冻结状态,保持最后姿态
状态转换逻辑:
javascript复制if (isVSign) {
systemState = 'IDLE';
} else if (results.multiHandLandmarks?.length > 0) {
systemState = 'TRACKING';
lostHandFrames = 0;
} else if (lostHandFrames++ > LOST_TOLERANCE) {
systemState = 'FROZEN';
}
4.2 粒子着色器优化
自定义着色器实现了多种视觉效果:
- 距离雾化:远处的粒子会淡出
- 动态噪声:近距离时添加扰动效果
- 颜色渐变:基于缩放级别调整粒子颜色
顶点着色器核心代码:
glsl复制if (dist < 25.0 && dist > 0.1) {
float chaos = pow(1.0 - (dist / 25.0), 3.0) * 3.0;
float ht = uTime * 40.0;
vec3 noiseVec = vec3(sin(ht + pos.x * 10.0) * hash(pos.y),
cos(ht + pos.y * 10.0) * hash(pos.x),
sin(ht * 0.5) * hash(pos.z));
mvPosition.xyz += noiseVec * chaos;
}
4.3 性能优化技巧
- 粒子剔除:基于随机ID和缩放级别动态剔除不可见粒子
- 像素比限制:防止在高DPI设备上过度渲染
- 平滑过渡:所有参数变化都使用插值避免突变
关键优化代码:
javascript复制renderer = new THREE.WebGLRenderer({
antialias: false,
alpha: true,
powerPreference: "high-performance"
});
renderer.setPixelRatio(Math.min(window.devicePixelRatio, CONFIG.pixelRatioLimit));
5. 开发经验与技巧
5.1 手势识别优化
- 平滑滤波:所有手势参数都经过低通滤波处理,避免抖动
- 死区处理:在中心位置设置小的不敏感区域
- 手势优先级:比耶手势优先于其他手势识别
5.2 Three.js性能优化
- 使用BufferGeometry:比常规Geometry性能更高
- 自定义着色器:实现特殊效果的同时保持高性能
- 合理设置粒子数量:在效果和性能间取得平衡
5.3 常见问题解决
-
手势识别不稳定
- 调整minDetectionConfidence和minTrackingConfidence参数
- 增加平滑滤波系数
- 优化光照条件
-
粒子渲染性能差
- 减少粒子总数
- 简化着色器计算
- 使用更高效的粒子剔除策略
-
状态切换不流畅
- 确保所有参数都有平滑过渡
- 使用一致的插值函数
- 避免在状态切换时重置所有参数
6. 项目扩展思路
- 多手势支持:增加更多复杂手势控制
- 物理模拟:为粒子添加简单的物理效果
- 多人互动:支持多个用户同时控制不同部分
- VR/AR集成:移植到VR/AR环境中
- 参数自定义:允许用户调整粒子外观和行为
这个项目展示了Web技术在交互式3D可视化方面的强大能力。通过结合计算机视觉和实时图形渲染,我们能够创建出既美观又富有交互性的体验。这种技术组合在数字艺术、教育演示、产品展示等领域都有广泛的应用前景。