如何在纯前端中通过手势交互来控制星球的转动

如何在纯前端中通过手势交互来控制星球的转动

技术栈

  • MediaPipe Hands - Google 的开源手部追踪库
  • Three.js - 3D 渲染引擎
  • 摄像头实时视频流输入

项目地址粒子土星


手势交互核心实现流程

步骤0:CDN导入

html 复制代码
<!-- MediaPipe 核心库 -->
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/hands/hands.js"></script>

<!-- Three.js (如果需要3D渲染) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>

步骤1: 初始化手势检测器

js 复制代码
const hands = new Hands({
  locateFile: (file) => {
    return `https://cdn.jsdelivr.net/npm/@mediapipe/hands/${file}`;
  }
});

hands.setOptions({
  maxNumHands: 1,           // 只检测一只手
  modelComplexity: 1,       // 模型复杂度(0-1)
  minDetectionConfidence: 0.7,  // 检测置信度阈值
  minTrackingConfidence: 0.7    // 追踪置信度阈值
});

步骤2: 启动摄像头并持续检测

js 复制代码
const cameraUtils = new Camera(videoElement, {
  onFrame: async () => {
    await hands.send({ image: videoElement });  // 每帧都发送给模型分析
  },
  width: 640,
  height: 480
});
cameraUtils.start();

步骤3: 处理检测结果 - 两个关键手势映射

🤏 手势1: 缩放控制 (拇指+食指距离)
js 复制代码
// 获取拇指尖端(landmark 4)和食指尖端(landmark 8)
const p1 = hand[4];  // 大拇指指尖
const p2 = hand[8];  // 食指指尖

// 计算两点间的欧氏距离
const dist = Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);

// 归一化到 [0, 1] 区间,然后映射到缩放范围 [0.15, 2.5]
const normDist = Math.max(0, Math.min(1, (dist - 0.02) / 0.25));
targetScale = 0.15 + normDist * 2.35;

效果 : 👌捏合手指 = 缩小 | ✋张开手指 = 放大

✋ 手势2: 俯仰角控制 (手掌Y轴位置)
复制代码
// 使用手腕位置(landmark 9)的Y坐标
const y = hand[9].y;  // 手掌中心点

// 归一化Y坐标到 [0, 1],映射到旋转角度 [-0.6, 1.0] 弧度
const normY = Math.max(0, Math.min(1, (y - 0.1) / 0.8));
targetRotX = -0.6 + normY * 1.6;

效果 : 🖐️手掌上移 = 向上看 | 🖐️手掌下移 = 向下看

项目中其他方面设计

平滑动画系统

为了让动作不卡顿,使用了 线性插值(Lerp) :

复制代码
const lerpFactor = 0.08;  // 插值系数,越小越平滑
currentScale += (targetScale - currentScale) * lerpFactor;
currentRotX += (targetRotX - currentRotX) * lerpFactor;

自动巡航模式

当没有检测到手时,进入自动巡航:

js 复制代码
if (!isHandDetected) {
  autoIdleTime += 0.005;
  targetScale = 1.0 + Math.sin(autoIdleTime) * 0.2;      // 自动缩放呼
  吸效果
  targetRotX = 0.4 + Math.sin(autoIdleTime * 0.3) * 0.15; // 自动轻微摇
  摆
}

Shader中的实际应用

手势控制的值最终传递给GPU着色器:

js 复制代码
uniforms.uScale.value = currentScale;      // 控制土星大小
uniforms.uRotationX.value = currentRotX;   // 控制视角俯仰

在GLSL着色器中应用旋转:

js 复制代码
// 处理整体视角的 X 轴旋转(即手势控制的俯仰角)
float cx = cos(uRotationX);
float sx = sin(uRotationX);
float ry = pos.y * cx - pos.z * sx;
float rz = pos.y * sx + pos.z * cx;
pos.y = ry;
pos.z = rz;

作者 :NotSleeply | 项目地址粒子土星

相关推荐
用户0595401744628 分钟前
把待办应用从Electron换成Tauri,内存占用狂降90%,打包体积仅5MB
前端·css
假如让我当三天老蒯29 分钟前
回归基本功!前端的解构赋值、扩展运算符、剩余参数
前端·面试
bonechips42 分钟前
JS 数组指南:从内存原理到二维矩阵
前端·javascript
亿元程序员1 小时前
美术妹子让我给模型加个描边,我差点把Cocos卸了
前端
IT_陈寒1 小时前
React的useEffect依赖数组把我坑惨了,真相其实很简单
前端·人工智能·后端
徐小夕1 小时前
JitWord 3.0 正式发布,高精度Word异构解析+复杂组件兼容,打造web端协同Word编辑器
前端·vue.js·算法
恋猫de小郭1 小时前
KMP / CMP 鸿蒙版本 Beta 发布,他有什么特别之处?
android·前端·flutter
乘风gg2 小时前
OpenClaw 爆火,但”飞书"赢麻了!!!
前端·ai编程·claude