AI真好玩系列-WebGL爱心粒子手势互动教程 | Interactive Heart Particles with Hand Gestures

news/2025/12/6 23:45:51/文章来源:https://www.cnblogs.com/sugartang/p/19316853

AI真好玩系列-WebGL爱心粒子手势互动教程 | Interactive Heart Particles with Hand Gestures

周末的深夜,睡不着觉,闲来无事,打开Gemini哈基米玩一把,废话不多说,先上图看最终效果~

碎碎念:我很想上传视频,但是好像有的博客不支持,这里先放个图片

视频地址:https://www.bilibili.com/video/BV1Q92RBoE6F?t=4.9

image

image

💖 提示词

创建一个基于WebGL的交互式3D网页,通过摄像头检测用户手掌的张合,实时控制由粒子构成的爱心模型的聚散状态。

image

📚 项目代码

<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title>WebGL 手势控制爱心粒子</title><style>body { margin: 0; overflow: hidden; background-color: #000; }#canvas-container { width: 100vw; height: 100vh; position: absolute; top: 0; left: 0; z-index: 1; }/* 隐藏摄像头视频流,只用于后台分析 */.input_video { display: none; }#loading {position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);color: white; font-family: sans-serif; font-size: 24px; pointer-events: none; z-index: 10;}</style><!-- 引入 Three.js --><script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script><!-- 引入 MediaPipe Hands --><script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/@mediapipe/control_utils/control_utils.js" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/@mediapipe/hands/hands.js" crossorigin="anonymous"></script>
</head>
<body><div id="loading">正在加载模型与摄像头...<br>请允许摄像头权限</div>
<div id="canvas-container"></div>
<video class="input_video"></video><script>// --- 1. Three.js 场景初始化 ---const scene = new THREE.Scene();const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);camera.position.z = 30;const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });renderer.setSize(window.innerWidth, window.innerHeight);document.getElementById('canvas-container').appendChild(renderer.domElement);// --- 2. 创建爱心粒子系统 ---const particleCount = 3000; // 粒子数量const geometry = new THREE.BufferGeometry();const positions = new Float32Array(particleCount * 3);const targetPositions = new Float32Array(particleCount * 3); // 存储爱心形状的目标位置const randomPositions = new Float32Array(particleCount * 3); // 存储散开时的随机位置// 爱心方程函数function getHeartPosition(t, scale = 1) {const x = 16 * Math.pow(Math.sin(t), 3);const y = 13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t);const z = 0; return { x: x * scale, y: y * scale, z: z * scale };}for (let i = 0; i < particleCount; i++) {// 生成爱心形状的目标点// 为了让爱心立体一点,我们随机分布t,并在Z轴加一点随机扰动const t = Math.random() * Math.PI * 2;const scale = 0.5; const heartPos = getHeartPosition(t, scale);// 填充爱心内部 (随机缩放)const r = Math.sqrt(Math.random()); targetPositions[i * 3] = heartPos.x * r;targetPositions[i * 3 + 1] = heartPos.y * r;targetPositions[i * 3 + 2] = (Math.random() - 0.5) * 5; // Z轴厚度// 生成散开的随机位置 (爆炸效果)randomPositions[i * 3] = (Math.random() - 0.5) * 100;randomPositions[i * 3 + 1] = (Math.random() - 0.5) * 60;randomPositions[i * 3 + 2] = (Math.random() - 0.5) * 50;// 初始位置设为散开状态positions[i * 3] = randomPositions[i * 3];positions[i * 3 + 1] = randomPositions[i * 3 + 1];positions[i * 3 + 2] = randomPositions[i * 3 + 2];}geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));// 粒子材质const material = new THREE.PointsMaterial({color: 0xff69b4, // 热粉色size: 0.4,transparent: true,opacity: 0.8,blending: THREE.AdditiveBlending});const particles = new THREE.Points(geometry, material);scene.add(particles);// --- 3. 交互逻辑变量 ---let gatherFactor = 0; // 0 = 完全散开, 1 = 完全聚合成爱心let targetGatherFactor = 0; // 目标聚合度,由手势控制// --- 4. MediaPipe Hands 配置 ---const videoElement = document.getElementsByClassName('input_video')[0];function onResults(results) {document.getElementById('loading').style.display = 'none';if (results.multiHandLandmarks && results.multiHandLandmarks.length > 0) {const landmarks = results.multiHandLandmarks[0];// 计算手掌开合程度// 简单算法:计算拇指指尖(4)与其他四指指尖(8,12,16,20)到手腕(0)的平均距离const wrist = landmarks[0];const fingerTips = [4, 8, 12, 16, 20];let totalDist = 0;fingerTips.forEach(idx => {const tip = landmarks[idx];const dist = Math.sqrt(Math.pow(tip.x - wrist.x, 2) + Math.pow(tip.y - wrist.y, 2));totalDist += dist;});const avgDist = totalDist / 5;// 经验阈值:// 握拳时,指尖距离手腕很近 (avgDist 约 0.1 - 0.2)// 张开时,指尖距离手腕较远 (avgDist 约 0.4 - 0.6)// 我们做一个映射:握拳(distance small) -> 聚合(factor 1), 张开 -> 散开(factor 0)// 动态调整这些阈值以适应摄像头的距离const closeThreshold = 0.25; const openThreshold = 0.5;let normalized = (avgDist - closeThreshold) / (openThreshold - closeThreshold);normalized = 1 - Math.min(Math.max(normalized, 0), 1); // 反转:距离越小(握拳),值越大(1)targetGatherFactor = normalized; } else {// 如果没有检测到手,默认缓慢散开targetGatherFactor = 0;}}const hands = new Hands({locateFile: (file) => {return `https://cdn.jsdelivr.net/npm/@mediapipe/hands/${file}`;}});hands.setOptions({maxNumHands: 1,modelComplexity: 1,minDetectionConfidence: 0.5,minTrackingConfidence: 0.5});hands.onResults(onResults);const cameraUtils = new Camera(videoElement, {onFrame: async () => {await hands.send({image: videoElement});},width: 640,height: 480});cameraUtils.start();// --- 5. 动画循环 ---function animate() {requestAnimationFrame(animate);// 粒子自身旋转动画particles.rotation.y += 0.002;// 平滑过渡聚合系数 (Lerp)gatherFactor += (targetGatherFactor - gatherFactor) * 0.05;// 更新粒子位置const posAttr = particles.geometry.attributes.position;const currentPositions = posAttr.array;for (let i = 0; i < particleCount; i++) {const idx = i * 3;// 目标位置插值:从 randomPositions 过渡到 targetPositionsconst tx = randomPositions[idx] + (targetPositions[idx] - randomPositions[idx]) * gatherFactor;const ty = randomPositions[idx+1] + (targetPositions[idx+1] - randomPositions[idx+1]) * gatherFactor;const tz = randomPositions[idx+2] + (targetPositions[idx+2] - randomPositions[idx+2]) * gatherFactor;// 增加一点动态浮动效果currentPositions[idx] += (tx - currentPositions[idx]) * 0.1;currentPositions[idx+1] += (ty - currentPositions[idx+1]) * 0.1;currentPositions[idx+2] += (tz - currentPositions[idx+2]) * 0.1;}posAttr.needsUpdate = true;renderer.render(scene, camera);}animate();// 窗口大小调整适配window.addEventListener('resize', () => {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);});
</script>
</body>
</html>

🌟 项目简介 | Project Introduction

这是一个基于 Three.js 和 MediaPipe Hands 的前端交互项目。通过摄像头捕捉你的手势,你可以控制屏幕上的数千个爱心粒子聚拢或散开。握拳时爱心会聚拢成形,张开手掌时则会散落如星辰。是不是超级浪漫又有科技感呢?🥰

📌 前提条件 | Prerequisites

  1. 现代浏览器: Chrome/Firefox/Safari 最新版
  2. 摄像头设备: 内置或外接摄像头
  3. 基础 HTML/CSS/JS 知识: 有助于理解代码结构

🚀 核心技术栈 | Core Technologies

技术 用途 链接
Three.js WebGL 3D 渲染引擎 threejs.org
MediaPipe 手部关键点识别 mediapipe.dev
HTML5 Canvas 粒子渲染容器 -

💖 爱心数学公式 | Heart Math Formula

我们使用经典的爱心参数方程来生成粒子目标位置:

function getHeartPosition(t, scale = 1) {const x = 16 * Math.pow(Math.sin(t), 3);const y = 13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t);return { x: x * scale, y: y * scale, z: 0 };
}

这个方程可以绘制出完美的爱心轮廓,再配合粒子系统就能创造出梦幻的效果啦!💗

👐 手势识别原理 | Gesture Recognition Principle

通过 MediaPipe 获取手部 21 个关键点坐标,我们重点分析以下关键点:

  • 手腕(Wrist): 索引 0
  • 指尖(Finger Tips): 索引 4(拇指), 8(食指), 12(中指), 16(无名指), 20(小指)

计算各指尖到手腕的平均距离,以此判断握拳(爱心聚拢)或张开(爱心散开)状态。

🧩 核心代码片段 | Core Code Snippets

1. 粒子系统初始化 | Particle System Initialization

const particleCount = 3000;
const geometry = new THREE.BufferGeometry();
const positions = new Float32Array(particleCount * 3);
const targetPositions = new Float32Array(particleCount * 3);
const randomPositions = new Float32Array(particleCount * 3);// 初始化爱心目标位置和随机初始位置...

2. 手势控制逻辑 | Gesture Control Logic

function onResults(results) {if (results.multiHandLandmarks && results.multiHandLandmarks.length > 0) {const landmarks = results.multiHandLandmarks[0];// 计算平均指尖距离并映射到聚合因子...} else {targetGatherFactor = 0; // 默认散开}
}

3. 粒子动画循环 | Animation Loop

function animate() {requestAnimationFrame(animate);// 平滑过渡聚合系数gatherFactor += (targetGatherFactor - gatherFactor) * 0.05;// 更新每个粒子位置(从随机位置插值到爱心形状)for (let i = 0; i < particleCount; i++) {// 插值计算...}renderer.render(scene, camera);
}

🎨 视觉效果亮点 | Visual Highlights

  1. Additive Blending 加法混合: 粒子重叠时颜色叠加,营造梦幻光晕效果
  2. Smooth Lerp 平滑插值: 粒子移动自然流畅,无突兀感
  3. Dynamic Rotation 动态旋转: 整体粒子云缓慢自旋,增强视觉动感
  4. Responsive Design 响应式设计: 自动适配不同屏幕尺寸

🛠️ 使用指南 | Run Guide

本地运行 | Local Run

  1. 将代码保存为 heart.html
  2. 用现代浏览器直接打开即可(需允许摄像头权限)

🔧 定制项 | Customization Options

项目 修改方法 效果预览
粒子颜色 更改 color: 0xff69b4 💗 粉色爱心 → 💙 蓝色星辰
粒子大小 调整 size: 0.4 🌟 大颗粒 → ⭐ 小星星
粒子数量 修改 particleCount 🌌 稀疏星空 → 💫 浓密银河
形状变换 替换爱心方程 ❤️ 爱心 → 🌸 樱花

🐛 常见问题 | Troubleshooting

  1. 摄像头无法启动?

    • 检查浏览器权限设置
    • 确保没有其他程序占用摄像头
  2. 手势识别不准确?

    • 保持手部在摄像头清晰可见范围内
    • 调整环境光线避免过暗或过曝
  3. 性能卡顿怎么办?

    • 减少粒子数量 (particleCount)
    • 关闭其他占用资源的程序

📚 扩展学习资源 | Extended Resources

  • Three.js 官方文档
  • MediaPipe Hands 文档
  • WebGL Fundamentals 教程

Conclusion | 结语

  • That's all for today~ - | 今天就写到这里啦~

  • Guys, ( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ See you tomorrow~~ | 小伙伴们,( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ我们明天再见啦~~

  • Everyone, be happy every day! 大家要天天开心哦

  • Welcome everyone to point out any mistakes in the article~ | 欢迎大家指出文章需要改正之处~

  • Learning has no end; win-win cooperation | 学无止境,合作共赢

  • Welcome all the passers-by, boys and girls, to offer better suggestions! ~~~ | 欢迎路过的小哥哥小姐姐们提出更好的意见哇~~

image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/990665.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据分析基础及应用案例:第八周学习报告——深度学习与金融案例入门

在金融科技飞速发展的当下,深度学习技术正深刻重塑着金融领域的研究与应用范式。第七周的学习围绕 “深度学习与金融案例入门” 展开,从 LSTM 模型到情感计算分析基础,再到证券文本情感分析的背景与数据来源预习,每…

第47天(简单题中等题 数据结构)

打卡第四十七天 2道简单题+1道中等题题目:思路:代码: class Solution { public:vector<bool> isArraySpecial(vector<int>& nums, vector<vector<int>>& queries) {vector<int&…

SpyCloud数据揭示:企业用户遭遇钓鱼攻击的可能性是恶意软件的三倍

SpyCloud的最新研究报告显示,针对企业用户的钓鱼攻击在一年内激增了400%,成为比恶意软件更主要的初始入侵手段。文章分析了这种攻击趋势的转变,并探讨了身份数据暴露带来的后续风险以及企业所需的综合防护策略。Spy…

nccl-1_initialization bootstrap

nccl学习-1: 初始化communicator与bootstrap 网络 在nccl的例子中,当我们获取了设备的数量,为每一个设备分配了一个ncclComm_t后,需要根据已经固定的通信拓扑,对每一个算子进行配置。目前,针对communicator的初始…

2025年国内TOP5会计培训机构推荐,引领专业提升之路

在当前的会计培训市场中,各类机构提供了丰富的选择,以满足不同学员的需求。比如,成都环宇知了科技有限公司专注于基础课程,适合初学者。而超有爱教育培训则为在职人员开设了实用性强的课程,结合真实案例帮助学员提…

2025年国内TOP5会计培训机构推荐,引领专业提升之路

在当前的会计培训市场中,各类机构提供了丰富的选择,以满足不同学员的需求。比如,成都环宇知了科技有限公司专注于基础课程,适合初学者。而超有爱教育培训则为在职人员开设了实用性强的课程,结合真实案例帮助学员提…

2025年评价高的草本床垫供应厂家TOP5推荐

在2025年,市场上的草本床垫供应厂家层出不穷,每一家公司都在努力提升产品质量与用户体验。从材料选择到设计理念,众多厂家在不断创新。其中,四川宅逸居家居有限公司凭借其独特的草本助眠技术广受好评;而芬驰家居则…

2025 最新智能运维服务商/ 厂家 TOP5 评测!科技赋能 + 全周期服务权威榜单发布,引领智慧工厂运维新生态

随着智能制造的深入发展,智能运维作为保障工厂高效、稳定、绿色运行的核心环节,其重要性日益凸显。本榜单基于技术创新力、行业适配性、服务覆盖度、实战效果四大维度,结合行业权威数据与客户反馈,对2025年智能运维…

人生第一篇博客:千里之行,始于足下

现在是2025年12月6日晚,大二的我像一个刚闯入森林的探险者,好奇的注册了这个博客网站,四处打量着各个大佬写的高级的东西(看不懂)据说写博客是很多学计算机的人的好习惯,用来记录和监督自己一天的学习或者思考,…

全网热议!2025年比较好的全屋定制公司推荐

全屋定制市场在2025年展现出强劲的发展势头,吸引了越来越多的消费者关注。众多厂家如东莞市洋臣家具有限公司、志想家具和家思家具等,通过独特的设计理念和优质的服务,不断赢得市场口碑。这些品牌不仅注重产品的质量…

扩散炉供应厂家TOP推荐:2025年值得关注的优质厂家

在本文中,我们将深入探讨扩散炉供应厂家的TOP推荐榜单,以帮助您更好地了解当前市场上值得关注的优质厂家。首先,我们将列出排名前列的制造商,如青岛晨立电子有限公司、福润德和金瑞源,这些企业在质量、技术和服务…

2025年专业HIFI耳机口碑排行榜推荐,不容错过!

在2025年,专业HIFI耳机的市场持续发展,各品牌争相推出高品质耳机,吸引音响爱好者的关注。我们的推荐榜单中包括了市面上评价好的耳机,这些耳机不仅在音质表现上出众,还兼具外观设计美感和佩戴舒适性。东莞斯唯嘉电…

全网热议!2025年靠谱的全屋定制品牌推荐,让生活更智能

在2025年,全屋定制市场竞争愈加激烈,消费者对于家居环境的需求也日益提高。本文将介绍靠谱的全屋定制品牌TOP10,涵盖高端的全屋定制十大品牌以及广东全屋定制TOP前十,为寻找理想家居方案的客户提供实用参考。这些品…

Ancel AD410 OBD2 Scanner - Multi-Language OBD2 Code Reader Error Eraser for European American Cars

Why the Ancel AD410 OBD2 Scanner is Your Next Essential Diagnostic Tool Ever stared at your check engine light, only to be met with cryptic error codes that leave you guessing what’s wrong? Or spent …

2025年如何选择值得信赖的家居照明公司?

选择值得信赖的家居照明公司至关重要,尤其在现代智慧家居的背景下。消费者可以从多个方面进行评估,例如品牌的市场表现和用户反馈。关注照明公司的产品质量与创新技术,了解其是否将简约设计与智能科技相结合,为客户…

2025年护眼吸顶灯销售厂家有哪些?

护眼吸顶灯在现代家居和办公环境中扮演着重要角色。随着市场对健康照明需求的增加,越来越多的消费者开始关注自然光护眼吸顶灯,这些产品的设计理念是减少光线对眼睛的伤害。同时,选择合适的厂家也显得尤为重要。不同…

豆包碰壁微信,你只看热闹吗?个人数据归属的经济范式、法理解析 与我们的未来

我们的数据被割据在许多孤岛中 每个孤岛都可以成为利维坦 几天前,字节跳动携手中兴通讯,推出了基于人工智能操作系统(AIOS)的智能手机工程样机。这款手机允许后台调用APP,通过组合填制表单、模拟触屏等动作,实现…

20251206 之所思 - 人生如梦

20251206 之所思今天两件事做的特别糟糕:1) 早上起来太太要我帮她在手机上弄医保绑定的事情,因为我自己安排了事情,所以很不情愿,加上我本人最不喜欢的就是在手机上操作一些和政府部门单位相关的业务(界面恶心,…

一些心事

一些心事无有的时候觉得自己很想回家,但是回了家又想逃离。因为不论我在家待多久,总有一个时刻,或许是第一天,或许是最后一眼,我会猛的一下意识到,自己其实不属于这里。 这大部分原因是因为我妈。 从这个学期开始…

洛谷 P11345 [KTSC 2023 R2] 基地简化 题解

校内模拟赛题,倒在了正解前最后一步 qwq。 解题思路 首先,发现题目要求的东西很不好做。于是转化一下,考虑计算每条边对答案贡献了几次。 这样问题就转化成了求有多少个区间的点分布在一条边两端的两个子树中。 发现…