mediapipe+webgl摄像头识别手掌操控液态流体动画交互效果代码

代码语言:html

所属分类:动画

代码描述:mediapipe+webgl摄像头识别手掌操控液态流体动画交互效果代码,只能通过摄像头来识别双手移动来产生液态气体流动画。

代码标签: mediapipe webgl 摄像头 识别 手掌 操控 液态 流体 动画 交互

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>MediaPipe Fluid Control</title>

    <!-- 1. 引入依赖库 (CDN) -->
    <!-- GUI 控制面板 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.9/dat.gui.min.js"></script>
    
    <!-- MediaPipe 核心库 -->
    <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/hands/hands.js" crossorigin="anonymous"></script>

    <style>
        html, body {
            overflow: hidden;
            background-color: #000;
            margin: 0;
            width: 100%;
            height: 100%;
        }

        canvas {
            width: 100%;
            height: 100%;
            display: block;
        }

        /* 隐藏用于计算的视频元素 */
        .input_video {
            display: none;
        }

        /* 调整 GUI 位置 */
        .dg.ac {
            z-index: 999 !important;
        }
    </style>
</head>
<body>
    <!-- 渲染画布 -->
    <canvas></canvas>
    <!-- 摄像头输入源 -->
    <video class="input_video"></video>

<script>
'use strict';

// 定义全局 canvas 变量,供 WebGL 和 MediaPipe 使用
var canvas = document.getElementsByTagName('canvas')[0];
var videoElement = document.getElementsByClassName('input_video')[0];

// ==========================================
// 1. MediaPipe 手势识别逻辑
// ==========================================

// 初始化 Hands 模型
const hands = new Hands({locateFile: (file) => {
  return `https://cdn.jsdelivr.net/npm/@mediapipe/hands/${file}`;
}});

hands.setOptions({
  maxNumHands: 2,           // 最多识别2只手
  modelComplexity: 1,       // 模型复杂度,1是平衡,0是快但精度低
  minDetectionConfidence: 0.5,
  minTrackingConfidence: 0.5
});

hands.onResults(onHandsResults);

// 初始化摄像头
const camera = new Camera(videoElement, {
  onFrame: async () => {
    await hands.send({image: videoElement});
  },
  width: 640,
  height: 480
});
camera.start();

// 处理手势识别结果
function onHandsResults(results) {
  if (results.multiHandLandmarks) {
    // 确保 pointers 数组足够容纳识别到的手
    while (pointers.length < results.multiHandLandmarks.length) {
        pointers.push(new pointerPrototype());
    }

    // 遍历每一只识别到的手
    for (let i = 0; i < pointers.length; i++) {
        if (i < results.multiHandLandmarks.length) {
            const landmarks = results.multiHandLandmarks[i];
            
            // 使用中指根部 (索引 9) 作为控制点,比指尖更稳定
            const handPoint = landmarks[9]; 
            
            // 坐标映射:
            // MediaPipe x: 0(左) -> 1(右)
            // 镜像反转 x: (1.0 - x) 以符合人类对镜子的直觉
            // 修复点:这里之前使用了 canvasElement 导致报错,现在统一为 canvas
            const posX = (1.0 - handPoint.x) * canvas.width;
            const posY = handPoint.y * canvas.height;

            const pointer = pointers[i];
            
            // 模拟鼠标交互逻辑
            if (!pointer.down) {
                // 手刚出现,视为“按下”
                updatePointerDownData(pointer, i, posX, posY);
            } else {
                // 手移动中,视为“拖拽”
                updatePointerMoveData(pointer, posX, posY);
            }
        } else {
            // 如果这只手消失了,视为“抬起”
            if (pointers[i].down) {
                updatePointerUpData(pointers[i]);
            }
        }
    }
  }
}


// ==========================================
// 2. WebGL 流体模拟引擎 (核心算法)
// ==========================================

resizeCanvas();

var config = {
    SIM_RESOLUTION: 128,
    DYE_RESOLUTION: 1024,
    CAPTURE_RESOLUTION: 512,
    DENSITY_DISSIPATION: 1,
    VELOCITY_DISSIPATION: 0.2,
    PRESSURE: 0.8,
    PRESSURE_ITERATIONS: 20,
    CURL: 30,
    SPLAT_RADIUS: 0.25,
    SPLAT_FORCE: 6000,
    SHADING: true,
    COLORFUL: true,
    COLOR_UPDATE_SPEED: 10,
    PAUSED: false,
    BACK_COLOR: { r: 0, g: 0, b: 0 },
    TRANSPARENT: false,
    BLOOM: true,
    BLOOM_ITERATIONS: 8,
    BLOOM_RESOLUTION: 256,
    BLOOM_INTENSITY: 0.8,
    BLOOM_THRESHOLD: 0.6,
    BLOOM_SOFT_KNEE: 0.7,
    SUNRAYS: true,
    SUNRAYS_RESOLUTION: 196,
    SUNRAYS_WEIGHT: 1.0,
}

function pointerPrototype () {
    this.id = -1;
    this.texcoordX = 0;
    this.texcoordY = 0;
    this.prevTexcoordX = 0;
    this.prevTexcoordY = 0;
    this.deltaX = 0;
    this.deltaY = 0;
    this.down = false;
    this.moved = false;
    this.color = [30, 0, 300];
}

var pointers = [];
var splatStack = [];
pointers.push(new pointerPrototype());

var ref = getWebGLContext(canvas);
var gl = ref.gl;
var ext = ref.ext;

if (isMobile()) {
    config.DYE_RESOLUTION = 512;
}
if (!ext.supportLinearFiltering) {
    config.DYE_RESOLUTION = 512;
    config.SHADING = false;
    config.BLOOM = false;
    config.SUNRAYS.........完整代码请登录后点击上方下载按钮下载查看

网友评论0