发布于 2026-01-05 0 阅读
0

JavaScript 速成:用手控制 3D 物体🤯 手部技巧 XenoX Multiverse DEV 全球展示挑战赛,由 Mux 呈现:展示你的项目!

JavaScript 速成:用手控制 3D 物体🤯

手部戏法

XenoX 多元宇宙

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

大家好!我们XenoX团队非常激动地宣布,我们将推出一个名为“JavaScript速成”的全新系列文章。在这个系列中,我们将分享一些可以用JavaScript快速完成的小实验,帮助大家探索新技术。得益于JavaScript,我们可以轻松地集成各种模块,创造无限可能。唯一的限制就是你的想象力。

想法💡

我们每个人都有自己最喜欢的科幻电影片段。对于我们这些开发者来说,这些片段格外珍贵,因为我们总是忍不住去想,那些银幕上炫酷的科幻特效该如何变成现实。每当我看到类似的场景,我的大脑就会立刻高速运转,开始思考各种技术上的可能性。这种感觉就像孩童般充满好奇,我非常喜欢。

我记得十几岁时看过《钢铁侠》,当时被他在实验室里与全息物体互动的场景深深震撼。回忆起那个场景,我不禁思考自己是否也能创造出类似的东西,一些能带来同样喜悦的东西。

当然,我们目前还没有完全掌握那种尖端技术来做出完全相同的效果。但我们完全可以利用现有的技术做出同样酷炫的东西。所以我周末做了这个小项目,想和大家分享一下。

复仇者联盟,系好安全带!让我们来创造“手部魔术”

🤓立即体验🤓

要求🧺

我用原生 JavaScript 编写了这个程序。所以你需要具备 JavaScript 的基础知识才能理解本教程。除此之外,我还使用了两个库:
1. Three.js 👉🏼链接
2. Handtrack.js 👉🏼链接

就是这样。

现在开始写代码吧👩🏽‍💻

HTML 代码部分非常简单。我们只是在这里引入了库,并添加了 div 元素来在浏览器中渲染摄像头画面:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>The Hand Trick</title>
    <link rel="stylesheet" href="css/style.css" />
  </head>
  <body>
    <!-- Video for handtracker -->
    <div class="tracker">
      <video id="myvideo"></video>
      <canvas id="canvas" class="border"></canvas>
      <button id="trackbutton" disabled onclick="toggleVideo()">Button</button>
      <div id="updatenote">hello</div>
    </div>
    <div class="data">
      <div class="hand-1">
        <p id="hand-x">X: <span>0</span></p>
        <p id="hand-y">Y: <span>0</span></p>
      </div>
    </div>
    <script src="js/three.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/handtrackjs/dist/handtrack.min.js"></script>
    <script src="js/scene.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

完成上述步骤后,我们快速回到 JavaScript 部分。如果您熟悉 Three.js,可以跳过这部分。对于其他用户,我们在这里通过设置场景细节来创建一个场景。

// Setting scene for 3D Object
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
var vector = new THREE.Vector3();
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
Enter fullscreen mode Exit fullscreen mode

接下来,我们创建一个3D对象来渲染到场景中。这里我们将定义盒子的几何形状和网格材质类型。

// Creating 3D object
var geometry = new THREE.BoxGeometry(1, 2, 1);
var material = new THREE.MeshBasicMaterial({
  color: "rgba(3, 197, 221, 0.81)",
  wireframe: true,
  wireframeLinewidth: 1
});

var cube = new THREE.Mesh(geometry, material);

scene.add(cube);
camera.position.z = 5;
Enter fullscreen mode Exit fullscreen mode

如果你想让物体在三维空间中旋转,这一步是可选的。只是这样看起来更酷。

// Optional animation to rotate the element
var animate = function() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
};

animate();
Enter fullscreen mode Exit fullscreen mode

这就是使用 Three.js 需要做的全部工作。现在让我们来体验一下 Handtrack.js。

// Creating Canavs for video Input
const video = document.getElementById("myvideo");
const handimg = document.getElementById("handimage");
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
let trackButton = document.getElementById("trackbutton");
let updateNote = document.getElementById("updatenote");

let imgindex = 1;
let isVideo = false;
let model = null;

// Params to initialize Handtracking js
const modelParams = {
  flipHorizontal: true,
  maxNumBoxes: 1,
  iouThreshold: 0.5,
  scoreThreshold: 0.7
};

handTrack.load(modelParams).then(lmodel => {
  model = lmodel;
  updateNote.innerText = "Loaded Model!";
  trackButton.disabled = false;
});
Enter fullscreen mode Exit fullscreen mode

我们在这里定义加载 Handtrack.js 的参数,但这一步是可选的;您也可以传递一个空对象。该handTrack.load()方法将帮助您加载模型。Handtrack.js 加载完成后,让我们编写函数来将视频流加载到 HTML 中定义的 canvas 元素中。为此,我们将使用该handTrack.startVideo()方法。

// Method to start a video
function startVideo() {
  handTrack.startVideo(video).then(function(status) {
    if (status) {
      updateNote.innerText = "Video started. Now tracking";
      isVideo = true;
      runDetection();
    } else {
      updateNote.innerText = "Please enable video";
    }
  });
}

// Method to toggle a video
function toggleVideo() {
  if (!isVideo) {
    updateNote.innerText = "Starting video";
    startVideo();
  } else {
    updateNote.innerText = "Stopping video";
    handTrack.stopVideo(video);
    isVideo = false;
    updateNote.innerText = "Video stopped";
  }
}
Enter fullscreen mode Exit fullscreen mode

现在我们可以编写代码,从handtrack.js获取预测数据。

//Method to detect movement
function runDetection() {
  model.detect(video).then(predictions => {
    model.renderPredictions(predictions, canvas, context, video);
    if (isVideo) {
      requestAnimationFrame(runDetection);
    }
  });
}
Enter fullscreen mode Exit fullscreen mode

真正的诀窍🧙🏼‍♂️

以上代码基本上都可以从库的文档中复制粘贴。但真正的挑战在于如何将两者整合起来以获得所需的结果。

诀窍在于跟踪视频画布上手的坐标,并根据该坐标对 Three.js 对象进行相应的更改。

prediction方法返回的对象如下model.detect()

{
  "bbox": [x, y, width, height],
  "class": "hand",
  "score": 0.8380282521247864
}
Enter fullscreen mode Exit fullscreen mode

bbox它会给出围绕手部绘制的方框的坐标、宽度和高度。但这些坐标并非方框的中心点坐标。要计算中心点坐标,我们使用以下简单公式:

 let midvalX = value[0] + value[2] / 2;
 let midvalY = value[1] + value[3] / 2;
Enter fullscreen mode Exit fullscreen mode

另一个问题是对象画布和跟踪器画布的尺寸都非常大。此外,这两个源的中心点都不在中心。为了解决这个问题,我们首先需要调整坐标,使视频画布的中心点位于中心。

完成这一步后,处理比例问题就很容易了。最终结果大概会是这样的。

//Method to detect movement
function runDetection() {
  model.detect(video).then(predictions => {
    model.renderPredictions(predictions, canvas, context, video);
    if (isVideo) {
      requestAnimationFrame(runDetection);
    }
    if (predictions.length > 0) {
      changeData(predictions[0].bbox);
    }
  });
}

//Method to Change prediction data into useful information
function changeData(value) {
  let midvalX = value[0] + value[2] / 2;
  let midvalY = value[1] + value[3] / 2;

  document.querySelector(".hand-1 #hand-x span").innerHTML = midvalX;
  document.querySelector(".hand-1 #hand-y span").innerHTML = midvalY;

  moveTheBox({ x: (midvalX - 300) / 600, y: (midvalY - 250) / 500 });
}

//Method to use prediction data to render cube accordingly
function moveTheBox(value) {
  cube.position.x = ((window.innerWidth * value.x) / window.innerWidth) * 5;
  cube.position.y = -((window.innerHeight * value.y) / window.innerHeight) * 5;
  renderer.render(scene, camera);
}
Enter fullscreen mode Exit fullscreen mode

好了,就是这样。现在你可以用手控制这个3D物体了。我已经把代码公开在GitHub上了,快去看看吧。克隆它,运行它,尽情体验吧!

GitHub 标志 sarthology / thehandtrick

🖐🏼 用手控制 3D 物体

手部戏法

演示

我们每个人都有自己最喜欢的科幻电影片段。对于我们这些开发者来说,这些片段格外珍贵,因为我们总是忍不住去想,那些银幕上炫酷的科幻特效该如何变成现实。每当我看到类似的场景,我的大脑就会立刻高速运转,开始思考各种技术上的可能性。这种感觉就像孩童般充满好奇,我非常喜欢。

我记得十几岁时看过《钢铁侠》,当时被他在实验室里与全息物体互动的场景深深震撼。回忆起那个场景,我不禁思考自己是否也能创造出类似的东西,一些能带来同样喜悦的东西。

点击此处查看教程

先决条件

在本地运行此程序之前,您必须已安装以下软件。

  • Three.js
  • Handtrack.js

加入我们

参与最酷的项目,加入我们……

总结一下👋🏻

故事才刚刚开始。这是本系列教程的第一篇,我计划将这个实验进一步推进。我非常希望有贡献者加入。如果您想为本项目做贡献,只需在XenoX Multiverse提交一个 pull request ,我就会与您联系。

XenoX 团队最初是由一群出于兴趣而开发开源项目的开发者组成的小团队。但几个月来,团队规模不断扩大,实力也日益增强。因此,我创建了 XenoX Multiverse,它是 XenoX 团队所有开源项目的聚集地。如果你想加入我们,只需留下你的名字,即可开始贡献代码!

在我离开之前

我们现在有 Dev.to 的 Telegram 频道啦!随时随地获取 Dev.to 的精彩内容,以及我们每天推送的外部文章、视频和投票!
👉🏼链接

我该走了。就到这里啦!记住,这只是一个快速实验,旨在激发你的创造力。你可以添加更多炫酷的功能,如果觉得运行缓慢,以后也可以优化代码。关键在于尽快学习新知识。希望你喜欢这篇文章。

回头见!

文章来源:https://dev.to/xenoxdev/javascript-quickies-controlling-3d-objects-with-hands-498n