#showdevJavaScript Quickies:用手控制3D对象?
嘿伙计们,怎么了?我们所有团队XenoX都非常高兴地通知您,我们正在开始一系列名为Javascript Quickies的新文章。这些将是您可以在Javascript中进行的快速实验,以探索新技术。感谢Javascript,我们可以插入各种模块并创建任何内容。你的想象力是唯一的限制。
想法?
我们都有科幻电影中最喜欢的时刻。这些时刻对于我们的开发者来说是特别的,因为我们不禁想知道我们在屏幕上看到的所有酷科幻技巧如何变成现实。每当我看到类似的东西时,我的思绪立即跳入最高档,我开始考虑所有的技术可能性。我非常喜欢这种孩子般的迷恋。
我记得像个青少年一样看着钢铁侠,并且对他在实验室里与全息物体互动的场景感到十分惊讶。当我回想起那个场景时,我开始思考是否可以创造出类似的东西,这种东西引发了同样的快乐。
当然,我们没有那么多汁技术来创造完全相同的效果,至少现在还没有。但我们肯定会尝试用我们已有的东西做一些酷炫的东西。所以我在周末做了这个很酷的小项目,与大家分享。
扣上,复仇者联盟让我们创造手伎俩。
?立即尝试?
要求?
我使用Vanilla Javascript制作了这个。因此,您应该对Javascript有基本的了解,以便理解本教程。除此之外,我在这里使用了两个库:
1. Three.js??链接
2. Handtrack.js??链接
而已。
我们现在编码???
代码的HTML方面非常简单。我们只是在这里包含库并添加div以在浏览器中呈现相机源:
LANG =“恩”> <元 字符集=“UTF-8” /> <元 名称=“视口” 内容=“width = device-width,initial-scale = 1.0” /> <元 HTTP的当量=“X-UA兼容” 内容=的“即=边缘” /> 手伎 <链接 相对=“样式” HREF =“CSS / style.css文件” />
CLASS =“跟踪器”> <视频 ID =“我的视频”> <画布 ID =“帆布” CLASS =“边界”> <按钮 ID =“trackbutton” 残 的onclick =“toggleVideo()”>按键 ID =“updatenote”>你好 CLASS =“数据”> CLASS =“手-1”> ID =“手X”>X: 0
ID =“便利”>Y: 0
完成后,让我们快速回到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);
之后,让我们创建一个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;
如果要在3D中旋转对象,则此步骤是可选的。它只是看起来很凉爽。
// 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();
这就是我们需要对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; });
我们在这里定义参数以加载Handtrack js,但这一步是可选的;你也可以传递一个空对象。该 handTrack.load()
方法将帮助您加载模型。一旦加载了handtrack js,让我们编写函数来加载html中定义的画布中的视频流。为此,我们正在使用 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"; } }
现在我们可以编写代码来从handtrack.js获取预测数据
//Method to detect movement function runDetection() { model.detect(video).then(predictions => { model.renderPredictions(predictions, canvas, context, video); if (isVideo) { requestAnimationFrame(runDetection); } }); }
真正的诡计??♂️
以上所有代码基本上都可以从库的文档中复制粘贴。但真正的挑战是将两者结合起来以获得理想的结果。
诀窍是在视频画布上跟踪手的坐标,并相对于三js对象进行更改。
该 prediction
对象来自 model.detect()
方法返回以下对象:
{ "bbox": (x, y, width, height), "class": "hand", "score": 0.8380282521247864 }
bbox
为您提供围绕手绘制的框的值坐标,宽度和高度。但坐标不是中心点。要计算中心点,我们使用这个简单的公式:
let midvalX = value(0) + value(2) / 2; let midvalY = value(1) + value(3) / 2;
另一个问题是对象的画布和跟踪器画布的比例很大。此外,两个源的中心点原点不是中心。为了解决这个问题,首先我们必须移动坐标,以便视频画布的原点可以居中。
完成后,处理比例问题很容易。所以最终的结果将是这样的。
//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); }
嗯,就是这样。您现在可以用手控制3D对象。我已经在Github公开了代码,所以去看看吧。克隆它,运行它,并享受它。
sarthology / thehandtrick
with用手控制3D物体
手伎
with用手控制3D物体
在GitHub上查看
总结??
故事刚刚开始。这是该系列的第一个教程,我计划将这个实验更进一步。我很想有一些贡献者。如果您想为项目做出贡献,只需在XenoX Multiverse上生成拉取请求,我就会与您联系。
XenoX团队起初是一个开发源项目的开发团队的小团队,为了它的乐趣。但几个月来,它变得越来越强大。这就是为什么我创建了XenoX Multiverse,它是XenoX团队所有开源计划的基地。如果你想成为我们中的一员,只需写下你的名字并开始贡献
在我走之前
我们现在有Dev.to的电报频道随时随地获取最好的Dev.to,以及我们每天发送的外部文章,视频和民意调查
??链接
现在是时候走了。总而言之,伙计们请记住,这只是一个快速的实验,可以帮助您获得创意。您可以为此添加更多很酷的功能,如果您觉得它运行缓慢,您可以稍后优化代码。关键是要尽快学习新东西。希望你喜欢这篇文章。
再见