UnityLeapMotion流程记录

突然接到一个LeapMotion的项目,回想起上次做LeapMotion还是在几年前,但是当时没有去记录,所以这次就相当于是重新走了一遍流程。很苦恼,赶紧记录下来。防止之后忘记。这次的需求还是比较简单的,用手滑动控制图片序列播放。

准备

  • Unity版本2021.3.19f1c1
  • LeapMotion一台

开始接入

Downloads – Page Array – Ultraleap

首先来到官网下载LeapMotion的必备组件

选择对应的设备,我这台设备是比较旧的。

无脑安装

安装好后还需要来到github页面下载unity-leapmotion的插件

https://github.com/ultraleap/UnityPlugin

然后导入到unity工程中

导入后找到Capsule Hands场景就是官方的示例

针对需求查看了官网文档。有两种想法:

  1. 通过XRXRI and XRHands Integration - Ultraleap documentation

去用手滑动UI。

  1. 获取手部追踪数据,用程序去判断,得到值,然后去改变视频的帧。

最终选择了第二种方法,觉得第二种比较简单。

创建HandControl.cs脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using Leap;
using Leap.Unity;

public class HandControl : MonoBehaviour
{

	public static bool Gesture_left = false;
	public static bool Gesture_right = false;
	public static bool Gesture_up = false;
	public static bool Gesture_down = false;
	public static bool Gesture_zoom = false;
	public static float movePOs = 0.0f;

	private LeapProvider mProvider;
	private Frame mFrame;
	private Hand mHand;

	public ImageSwitcher imageSwitcher;


	private Vector3 leftPosition;
	private Vector3 rightPosition;
	public static float zoom = 1.0f;
	[Tooltip("Velocity (m/s) of Palm ")]

	public float smallestVelocity = 1.45f;//手掌移动的最小速度

	[Tooltip("Velocity (m/s) of Single Direction ")]
	[Range(0, 1)]
	public float deltaVelocity = 1.0f;//单方向上手掌移动的速度

	// Use this for initialization
	void Start()
	{
		mProvider = FindObjectOfType<LeapProvider>() as LeapProvider;
	}

	// Update is called once per frame
	void Update()
	{

		mFrame = mProvider.CurrentFrame;//获取当前帧
										//获得手的个数
										//print ("hand num are " + mFrame.Hands.Count);

		if (mFrame.Hands.Count > 0)
		{
			
			if (mFrame.Hands.Count == 2)
				zoom = CalcuateDistance(mFrame);

			if (mFrame.Hands.Count == 1)
				LRUDGestures(mFrame, ref movePOs);
		}
	}


	float CalcuateDistance(Frame mFrame)
	{
		Gesture_zoom = true;
		Gesture_left = false;
		Gesture_right = false;

		float distance = 0f;
		//print ("Two hands");
		foreach (var itemHands in mFrame.Hands)
		{
			if (itemHands.IsLeft)
			{
				leftPosition = itemHands.PalmPosition;
				//print ("leftPosition" + leftPosition);
			}
			if (itemHands.IsRight)
			{
				rightPosition = itemHands.PalmPosition;
				//print ("rightPosition" + rightPosition);
			}
		}

		if (leftPosition != Vector3.zero && rightPosition != Vector3.zero)
		{

			Vector3 leftPos = new Vector3(leftPosition.x, leftPosition.y, leftPosition.z);
			Vector3 rightPos = new Vector3(rightPosition.x, rightPosition.y, rightPosition.z);

			distance = 10 * Vector3.Distance(leftPos, rightPos);
			//print("distance" + distance);
		}

		if (distance != 0)
			return distance;
		else
			return distance = 1;
	}




	void LRUDGestures(Frame mFrame, ref float movePOs)
	{
		Gesture_zoom = false;
		foreach (var item in mFrame.Hands)
		{
			int numFinger = item.Fingers.Count;
			//print ("item is  " + numFinger);

			//print("hand are " + isOpenFullHand (item));
			// print ("isOpenFullHands is  " + isOpenFullHands(item));


			if (item.GrabStrength == 1)
			{
				

			}
			else if (item.GrabStrength == 0)
			{
				//print ("num is 5, open your hand");
				//print("PalmVelocity" + item.PalmVelocity);
				//print("PalmPosition" + item.PalmPosition);
				movePOs = item.PalmPosition.x;
				if (isMoveLeft(item))
				{
					Gesture_left = true;
					Gesture_right = false;
					//print("move left");

				}
				else if (isMoveRight(item))
				{
					Gesture_left = false;
					Gesture_right = true;
					//print("move Right");

				}
				else if (isMoveUp(item))
				{
					Gesture_left = false;
					Gesture_right = false;
					print("move Up");
					imageSwitcher.PreviousImage();
				}
				else if (isMoveDown(item))
				{
					Gesture_left = false;
					Gesture_right = false;
					print("move Down");
					imageSwitcher.NextImage();

				}
				else if (isMoveForward(item))
				{
					Gesture_left = false;
					Gesture_right = false;
					print("move Forward");
					imageSwitcher.PreviousImage();
				}
				else if (isMoveBack(item))
				{
					Gesture_left = false;
					Gesture_right = false;
					print("move back");
					imageSwitcher.NextImage();
				}
			}
		}
	}



	private bool isStone(Hand hand)
	{
		//print ("hand.GrabAngle" + hand.GrabAngle);
		return hand.GrabStrength > 2.0f;
	}
	//是否抓取
	public bool isGrabHand(Hand hand)
	{
		return hand.GrabStrength > 0.8f;        //抓取力 
	}


	//hand move four direction
	public bool isMoveRight(Hand hand)
	{

		return hand.PalmVelocity.x > deltaVelocity && !isStationary(hand);
	}

	// 手划向右边
	public bool isMoveLeft(Hand hand)
	{

		//print (hand.PalmVelocity.x );
		return hand.PalmVelocity.x < -deltaVelocity && !isStationary(hand);
	}

	//手向上 
	public bool isMoveUp(Hand hand)
	{
		//print ("hand.PalmVelocity.y" + hand.PalmVelocity.y);

		return hand.PalmVelocity.y > deltaVelocity && !isStationary(hand);
	}

	//手向下  
	public bool isMoveDown(Hand hand)
	{
		return hand.PalmVelocity.y < -deltaVelocity && !isStationary(hand);
	}


	//手向前
	public bool isMoveForward(Hand hand)
	{
		//print (hand.PalmVelocity.z);
		return hand.PalmVelocity.z > deltaVelocity && !isStationary(hand);
	}

	//手向后 
	public bool isMoveBack(Hand hand)
	{
		return hand.PalmVelocity.z < -deltaVelocity && !isStationary(hand);
	}

	//固定不动的
	public bool isStationary(Hand hand)
	{
		return hand.PalmVelocity.magnitude < smallestVelocity;      //Vector3.Magnitude返回向量的长度
	}


}

创建ImageSwitcher.cs脚本

using UnityEngine;
using UnityEngine.UI; // 引入UI命名空间

public class ImageSwitcher : MonoBehaviour
{
    public Image displayImage; // 用于显示图片的Image组件
    public Sprite[] images; // 存储所有图片的数组
    private int currentImageIndex = 0; // 当前显示的图片索引

    void Start()
    {
        // 初始化时显示第一张图片
        if (images.Length > 0)
        {
            displayImage.sprite = images[currentImageIndex];
        }
    }

    // 切换到下一张图片
    public void NextImage()
    {
        if (images.Length > 0)
        {
            currentImageIndex = (currentImageIndex + 1) % images.Length; // 使用模运算确保索引循环
            displayImage.sprite = images[currentImageIndex];
        }
    }

    // 切换到上一张图片
    public void PreviousImage()
    {
        if (images.Length > 0)
        {
            currentImageIndex = (currentImageIndex - 1 + images.Length) % images.Length; // 使用模运算确保索引循环
            displayImage.sprite = images[currentImageIndex];
        }
    }
}

将两个脚本挂载在场景中并赋值

image switcher中的images将准备好的序列帧拖入

创建Canvas和Image。将image拖入image Switcher中

最终场景是这样的结构。使用的场景是官方的Capsule Hands。

成功运行。这个项目比较简单,开发的时候也没有遇到坑,在此记录下防止后面忘了流程。

官方文档

Get started with our plugins for XR developers - Ultraleap documentation

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

高速服务区智慧公厕管理系统引导屏UI界面展示

在现代社会&#xff0c;高速服务区作为人们出行途中的重要休憩场所&#xff0c;其各项设施的智能化水平也在不断提升。其中&#xff0c;智慧公厕管理系统的出现&#xff0c;为人们带来了更加便捷、舒适的如厕体验&#xff0c;而引导屏 UI 界面更是这一系统的重要展示窗口。 智慧…

FinalShell 配置SSH密钥登陆

转载请标明出处&#xff1a;http://blog.csdn.net/donkor_/article/details/139355489 文章目录 前言生成密钥服务器配置公钥本地配置私钥存储私钥FinalShell配置 总结 前言 本机FinalShell 配置SSH密钥登陆服务器&#xff0c;这样就不再需要使用密码进行登陆了。由于FinalSh…

hadoop(1)--hdfs部署(亲测可用)

一、准备&#xff1a; 1、三台集群部署&#xff0c;配置hosts #cat /etc/hosts 192.168.46.128 node1 #nameNode dataNode secondaryNameNode 192.168.46.129 node2 #datanode 192.168.46.130 node3 #datanode说明&#xff1a; NameNode: 主节点管理者 DataNode&…

AI+教育:OpenAI推出ChatGPT Edu教育版

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

Java web应用性能分析之【压测工具ab】

常用的性能测试工具有&#xff1a;JMeter、loadRunner、ab&#xff1b;对于开发人员来说用的多的是免费的Jmeter和ab&#xff0c;对于测试来说可能用收费的商业软件loadRunner多。在这里我们就说说ab压测工具&#xff0c;因为ab基本满足web接口测试要求&#xff0c;jmeter后面再…

开发者工具-sources(源代码选项)

一、概要说明 源代码面板从视觉效果上分为三个区域&#xff1a;菜单区、内容区、监听区。 菜单区里面有5个子分类&#xff1a; 网页(Page)&#xff1a;指页面源&#xff0c;包含了该页面中所有的文件&#xff0c;即使多个域名下的文件也都会展示出来&#xff0c;包括iframe…

【网络层】IP地址基础 与 子网掩码

文章目录 IP地址基础IP地址概念IP地址分类公网地址和私网地址 子网掩码子网掩码作用默认子网掩码网络地址、主机地址、广播地址 IP地址基础 IP地址概念 IP地址&#xff1a;IP Address 在网络中&#xff0c;通信节点都需要有一个IP地址 IP地址以点分十进制表示&#xff0c;有…

openresty(Nginx) 配置 特殊URL 密码访问 使用htpasswd 配置 Basic_Auth登录认证

1 使用htpasswd 生成密码文件.htpasswd是Apache附带的工具。如果没有可以安装。 #centos 8.5 系统 yum install httpd-tools #Ubuntu 24.04 系统 sudo apt update sudo apt-get install apache2-utils #生成密码文件,用户test sudo htpasswd -c /usr/local/openresty/nginx/…

Python魔法之旅-魔法方法(07)

目录 一、概述 1、定义 2、作用 二、应用场景 1、构造和析构 2、操作符重载 3、字符串和表示 4、容器管理 5、可调用对象 6、上下文管理 7、属性访问和描述符 8、迭代器和生成器 9、数值类型 10、复制和序列化 11、自定义元类行为 12、自定义类行为 13、类型检…

Matlab操作Excel筛选指定数据的对应数据

Matlab中在表格中寻找指定汉字&#xff0c;并返回其所在行数&#xff0c; 将该行数的另一列提取出来。 目录 一、前言 二、直接在命令行输出 三、保存筛选数据excel 一、前言 源数据excel&#xff1a; 指定汉子&#xff1a;买&#xff0c;得到下面数据&#xff1a; 二、直接…

特征工程技巧——OneHot编码

我们以Kaggle比赛里面的一个数据集跟一个公开代码为例去解释我们的OneHot编码。 简单来说&#xff0c;独热编码是一种将类别型变量转换为二进制表示的方法&#xff0c;其中每个类别被表示为一个向量&#xff0c;向量的长度等于类别的数量&#xff0c;其中只有一个元素为1&…

Kafka篇:Kafka搭建、使用、及Flink整合Kafka文档

一、Kafka搭建 1、上传并解压改名 tar -xvf kafka_2.11-1.0.0.tgz mv kafka_2.11-1.0.0 kafka-1.0.0 2、配置环境变量 vim /etc/profile export KAFKA_HOME/usr/local/soft/kafka-1.0.0 export PATH$PATH:$KAFKA_HOME/bin source /etc/profile &#xff08;使环境变量生效…

05.k8s弹性伸缩

5.k8s弹性伸缩 k8s弹性伸缩,需要附加插件heapster监控 弹性伸缩&#xff1a;随着业务访问量的大小&#xff0c;k8s系统中的pod比较弹性&#xff0c;会自动增加或者减少pod数量&#xff1b; 5.1 安装heapster监控 1:上传并导入镜像,打标签 ls *.tar.gz for n in ls *.tar.gz…

Linux下的Git应用

1、卸载 2、安装 3、创建并初始化 4、配置 &#xff08;附加删除语句&#xff09; 5、查看&#xff08;tree .git/&#xff09; 6、增加和提交 7、打印日志 8、验证已操作工作

7、css3实现边框不停地跑动效果

效果例图&#xff1a; 1、上html代码&#xff1a; <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><meta …

unity打包的WebGL部署到IIS问题

部署之后会出错&#xff0c;我遇到的有以下几种&#xff1b; 进度条卡住不动 明明已经部署到了IIS上&#xff0c;为什么浏览网页的时候还是过不去或者直接报错。 进度条卡住不动的问题其实就是wasm和data的错误。 此时在浏览器上按F12进入开发者模式查看错误&#xff08;下图…

USB主机模式——Android

理论 摘自&#xff1a;USB 主机和配件概览 | Connectivity | Android Developers (google.cn) Android 通过 USB 配件和 USB 主机两种模式支持各种 USB 外围设备和 Android USB 配件&#xff08;实现 Android 配件协议的硬件&#xff09;。 在 USB 主机模式下&#xff0…

香橙派 AIpro上手体验并验证车道线识别算法

香橙派 AIpro上手体验并验证车道线识别算法 1.前言 最近入手了一块香橙派AIpro&#xff0c;体验了一下&#xff0c;感觉还不错&#xff0c;在这里分享给大家&#xff0c;大家可以做个参考。 2.开箱 整套产品包含一块主板、一个电源插头和一条双端Type-C的数据线&#xff0c;…

jenkins本地打包远程部署项目

1、 Jenkins简介 Jenkins是一款开源的持续集成工具&#xff0c;用于自动化构建、测试和部署软件项目。它可以通过插件扩展来支持各种不同的开发语言和工具。Jenkins提供了一个简单易用的Web界面&#xff0c;可以通过界面配置和管理构建任务&#xff0c;也可以通过命令行工具进…

实物资产的市场主线将逐步回归

民生证券认为&#xff0c;投资者逐渐意识到长期趋势并没有发生变化&#xff0c;这或许正是本周最大的变化。在预期博弈重回冷静期后&#xff0c;去金融化背景下实物资源占优的市场主线也将逐步回归。 1 高低切换后的冷静期 从4月下旬至上周&#xff0c;A股市场呈现出由高位资产…