用htc vive手柄配对 开发,怎么确定手柄的位置变化 -

请完成以下验证码
您当前的位置: &
vive手柄按键开发说明
查看: 4501|
|原作者: 52vr.com
如何开发一款VR游戏,实现输入交互至关重要,我们先来看看在unity中如何对vive手柄进行编程,包括对手柄圆盘的使用说法。第一步,导入steamVR 插件和认识手柄:& &如图,我们已经导入了SteamVR Plugin,下面的SteamVR绿色图标表明Htc Vive的硬件也已经准备就绪,这是SteamVR_TestThrow场景,也是我们展开分析的入手点.这个测试很简单,就是你按下Trigger的时候,手柄上会实例化一个圆球+cube的结合体,当然松开Trigger的时候这个结合体就会脱离手柄,当然,你还可以施加一个扔的动作,这样的话结合体会有一个对应的加速度。手柄的按键说明图示:手柄是HTC Vive的重要交互手段,我们通过第一个图片应该对其有一个直观的了解了,总共是九个按钮:第一个是菜单按钮;2,3,4,5分别对应的是Trackpad/Touchpad的上下左右,有时候对应的是XBox手柄的▲OX囗四个按钮或者摇杆;6对应的是系统按钮/S7是Trigger/扳机,对应大多数FPS游戏里面的枪械的Shoot/F8对应的Grip/紧握在手柄的左右两侧各有一个,有时候我们用它来翻页;9其实是Trackpad/Touchpad在Z轴的一个延伸,相当于是点击事件Click.第二步:上代码说明如何控制:比较难明白的就是那个圆盘键,这个键是一个以中心为(0,0)点的直角坐标系,四个端长度都是1,可接收触摸和按压两种事件,见上图,触摸touch或按压press会通过GetAxis方法返回一个坐标系中的点,可以判断你按在哪里,触发不同的事件,可以根据角度或各种方法来切分按键为n个按钮。[代码]:using UnityE
using System.C
//检测手柄功能的脚本 这个脚本挂到手柄上(controler(right)和controler(left))上
public class ButtonTouchAction : MonoBehaviour {
SteamVR_TrackedObject trackdeO
void Awake() {
//获取手柄上的这个组件
trackdeObjec = GetComponent();
// Use this for initialization
void Start () {
void FixedUpdate()
//获取手柄输入
var device = SteamVR_Controller.Input((int)trackdeObjec.index);
//以下是api中复制出来的按键列表
public class ButtonMask
public const ulong System = (1ul && (int)EVRButtonId.k_EButton_System); // reserved
public const ulong ApplicationMenu = (1ul && (int)EVRButtonId.k_EButton_ApplicationMenu);
public const ulong Grip = (1ul && (int)EVRButtonId.k_EButton_Grip);
public const ulong Axis0 = (1ul && (int)EVRButtonId.k_EButton_Axis0);
public const ulong Axis1 = (1ul && (int)EVRButtonId.k_EButton_Axis1);
public const ulong Axis2 = (1ul && (int)EVRButtonId.k_EButton_Axis2);
public const ulong Axis3 = (1ul && (int)EVRButtonId.k_EButton_Axis3);
public const ulong Axis4 = (1ul && (int)EVRButtonId.k_EButton_Axis4);
public const ulong Touchpad = (1ul && (int)EVRButtonId.k_EButton_SteamVR_Touchpad);
public const ulong Trigger = (1ul && (int)EVRButtonId.k_EButton_SteamVR_Trigger);
//同样是三种按键方式,以后不做赘述
if (device.GetTouch(SteamVR_Controller.ButtonMask.Trigger)) {
Debug.Log("按了 “trigger” “扳机键”");
//右手震动
//拉弓类似操作应该就是按住trigger(扳机)gettouch时持续调用震动方法模拟弓弦绷紧的感觉。
var deviceIndex2 = SteamVR_Controller.GetDeviceIndex(SteamVR_Controller.DeviceRelation.Rightmost);
SteamVR_Controller.Input(deviceIndex2).TriggerHapticPulse(500);
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Trigger))
Debug.Log("按下了 “trigger” “扳机键”");
if (device.GetTouchUp(SteamVR_Controller.ButtonMask.Trigger)) {
Debug.Log("松开了 “trigger” “扳机键”");
//左手震动
var deviceIndex = SteamVR_Controller.GetDeviceIndex(SteamVR_Controller.DeviceRelation.Leftmost);
SteamVR_Controller.Input(deviceIndex).TriggerHapticPulse(3000);
//右手震动
var deviceIndex1 = SteamVR_Controller.GetDeviceIndex(SteamVR_Controller.DeviceRelation.Rightmost);
SteamVR_Controller.Input(deviceIndex1).TriggerHapticPulse(3000);
//这三种也能检测到 后面不做赘述
if(device.GetPressDown(SteamVR_Controller.ButtonMask.Trigger)) {
Debug.Log("用press按下了 “trigger” “扳机键”");
if (device.GetPress(SteamVR_Controller.ButtonMask.Trigger))
Debug.Log("用press按了 “trigger” “扳机键”");
if (device.GetPressUp(SteamVR_Controller.ButtonMask.Trigger))
Debug.Log("用press松开了 “trigger” “扳机键”");
//system键 圆盘下面那个键
// reserved 为Steam系统保留,用来调出Steam系统菜单 因此貌似自己加的功能没啥用
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.System))
Debug.Log("按下了 “system” “系统按钮/Steam”");
if (device.GetPressDown(SteamVR_Controller.ButtonMask.System))
Debug.Log("用press按下了 “System” “系统按钮/Steam”");
//ApplicationMenu键 带菜单标志的那个按键(在方向圆盘上面)
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.ApplicationMenu))
Debug.Log("按下了 “ApplicationMenu” “菜单键”");
if (device.GetPressDown(SteamVR_Controller.ButtonMask.ApplicationMenu))
Debug.Log("用press按下了 “ApplicationMenu” “菜单键”");
//Grip键 两侧的键 (vive雇佣兵游戏中的换弹键),每个手柄左右各一功能相同,同一手柄两个键是一个键。
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Grip))
Debug.Log("按下了 “Grip” “ ”");
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Grip))
Debug.Log("用press按下了 “Grip” “ ”");
//Axis0键 与圆盘有交互 与圆盘有关
//触摸触发
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Axis0))
Debug.Log("按下了 “Axis0” “方向 ”");
//按动触发
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Axis0))
Debug.Log("用press按下了 “Axis0” “方向 ”");
目前未发现按键位置
//触摸触发
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Axis1))
Debug.Log("按下了 “Axis1” “ ”");
//按动触发
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Axis1))
Debug.Log("用press按下了 “Axis1” “ ”");
//Axis2键 目前未发现按键位置
//触摸触发
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Axis2))
Debug.Log("按下了 “Axis2” “ ”");
//按动触发
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Axis2))
Debug.Log("用press按下了 “Axis2” “ ”");
未目前未发现按键位置
//触摸触发
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Axis3))
Debug.Log("按下了 “Axis3” “ ”");
//按动触发
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Axis3))
Debug.Log("用press按下了 “Axis3” “ ”");
目前未发现按键位置
//触摸触发
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Axis4))
Debug.Log("按下了 “Axis4” “ ”");
//按动触发
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Axis4))
Debug.Log("用press按下了 “Axis4” “ ”");
//方向圆盘:
//这里开始区分了press检测与touch检测的不同之处,圆盘可以触摸,顾名思义,touch检测的是触摸,press检测的是按动 //Axis0键 与圆盘有交互 与圆盘有关
//触摸触发
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Axis0))
Debug.Log("按下了 “Axis0” “方向 ”");
//按动触发
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Axis0))
Debug.Log("用press按下了 “Axis0” “方向 ”");
目前未发现按键位置
//触摸触发
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Axis1))
Debug.Log("按下了 “Axis1” “ ”");
//按动触发
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Axis1))
Debug.Log("用press按下了 “Axis1” “ ”");
//Axis2键 目前未发现按键位置
//触摸触发
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Axis2))
Debug.Log("按下了 “Axis2” “ ”");
//按动触发
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Axis2))
Debug.Log("用press按下了 “Axis2” “ ”");
未目前未发现按键位置
//触摸触发
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Axis3))
Debug.Log("按下了 “Axis3” “ ”");
//按动触发
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Axis3))
Debug.Log("用press按下了 “Axis3” “ ”");
目前未发现按键位置
//触摸触发
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Axis4))
Debug.Log("按下了 “Axis4” “ ”");
//按动触发
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Axis4))
Debug.Log("用press按下了 “Axis4” “ ”");
//ATouchpad键 圆盘交互
//触摸触发
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Touchpad))
Debug.Log("按下了 “Touchpad” “ ”");
//方法返回一个坐标 接触圆盘位置
Vector2 cc = device.GetAxis();
Debug.Log(cc);
// 例子:圆盘分成上下左右
float jiaodu = VectorAngle(new Vector2(1, 0), cc);
Debug.Log(jiaodu);
if (jiaodu & 45 && jiaodu & 135)
Debug.Log("下");
if (jiaodu & -45 && jiaodu & -135)
Debug.Log("上");
if ((jiaodu & 180 && jiaodu & 135) || (jiaodu & -135 && jiaodu & -180))
Debug.Log("左");
if ((jiaodu & 0 && jiaodu & 45) || (jiaodu & -45 && jiaodu & 0))
Debug.Log("右");
//按动触发
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Touchpad))
Debug.Log("用press按下了 “Touchpad” “ ”");
// Update is called once per frame
void Update () {
//方向圆盘最好配合这个使用 圆盘的.GetAxis()会检测返回一个二位向量,可用角度划分圆盘按键数量
//这个函数输入两个二维向量会返回一个夹角 180 到 -180
float VectorAngle(Vector2 from, Vector2 to)
Vector3 cross = Vector3.Cross(from, to);
angle = Vector2.Angle(from, to);
return cross.z & 0 ? -angle :
附上 vive手柄 3ds max模型下载:&下载地址:http://www.52vr.com/forum.php?mod=viewthread&tid=30301
52VR.COM微信扫一扫
专注于VR的学习、开发和人才交流
&津ICP备号&网安备57请完成以下验证码
您当前的位置: &
详细介绍Unity HTC VIVE 手柄如何接入
查看: 2925|
|来自: CSDN
一、资源导入从asset store 下载 SteamVR Plugin。然后导入Unity。将上图中的prefab拖入场景,然后在steam上装好steamVR,就可以运行了。二、手柄按键使用说明触控板的坐标如下图直接上代码,哪里不懂看注解就好。controller在刚才拖进场景的prefab里,如下图。[csharp]&&&
52VR.COM微信扫一扫
专注于VR的学习、开发和人才交流
&津ICP备号&网安备57HTC Vive controller手柄运动方向识别
HTC Vive controller手柄运动方向识别
本文由catzhang 编写,转载请注明出处,所有权利保留。
博客地址:
github地址:
使用Vive手柄,我们需要做一个简单的姿势识别,用来判断手柄的运动方向,然后我根据需要做了一个运动方向的识别,根据上下左右和各个夹角的方向,总共有八个方向。
功能:基本实现了手柄的八方向运动方向识别,也可以叫动作识别。识别精度和效率,可以根据参数来调整。
里面也附带了一个通过射线识别的方法,当然有缺点在后面也做了分析和说明,若有问题,还请不吝指教。
同样工程在后面会给出源码和unity包,还有图片路径地址。
二、 实现原理和实现过程
1 实现原理
原理很简单,就是根据路线,在一定时间内,记录路线数据,然后把数据映射到相机平面上,在根据取第一个点、中间点以及最后一个点,计算角度和斜率,在一定度数之内,都认为是某个方向的运行识别成功。
2 实现过程
1. 项目使用之前的vive消息解耦传递方法。
使用了Unity的5.4.0f3版本,也使用了之前的vive的Event项目的消息传递机制。
项目地址,把它放在了图说的工程中
希望有需要可以迁出和修改,提交,前几天也做了一点点的修改和提交。
当然,根据惯例,本项目的源码也会在项目后面分享出来,并给出到处的unity包,贴心吧。
2. 项目说明
打开下载好的项目,打开DemoScene中SteamVR_motion_direction_recongnize这个场景。
可以看到检视板中,内容不算多。
看看工程中大致的内容,包括样例场景,预制体对象,脚本和steamVR原插件中的内容。
当然SteamVR中代码已经做了部分修改,这个之前Event消息解耦使用所添加的一点点代码。
若你需要了解可以参考:
有不足之处还请不吝指教。
3. 对相机渲染层的设置
因为这里有Vive的头盔中项目camera(eye),需要把层设置为不渲染UI。
然后也同样对UI项目做了处理,让他只渲染UI。
4. 手柄运动方向识别
主要的脚本为:GestureJudge.cs。
我在场景中,只使用了右侧手柄来处理,这里没有在left左侧手柄挂载代码,若有需要,可以自己添加,是没有问题的。
可以通过调节参数来识别效果。
挥动超过距离:手柄在识别过程中的路线,必须大于一定长度才算数。这里设置的为0.8f.
数据跟踪的最短距离: 在同一个位置,间隔太小的手柄位置,不作为参考数据。手柄运动之间间隔大于这个值,才有效的位置数据。
检测周期:数值越大识别越容易。但是过大,就会提高误识别率。默认为0.15秒。测试结果到0.3s也是可以的,这个值作为参数吧。数据过了这个时间,就重新清零检测。
检测角度:我们本来检测的是八个方向,在把个方向一定角度内都算是某个方向的,这就是冗余,因为没有冗余,必须直直的路线才可以的。
5. 手柄路径标识
写了个小代码来标识手柄的运动路线。
就是在手柄的位置,每间隔一段距离就放置一个红色小球来表示。
标记手柄路经。
@cartzhang
public class CotrollerPathMark : MonoBehaviour
public GameO
public float StepDistance = 0.1f;
private Vector3 currentP
void Start ()
currentPos = this.transform.
void Update ()
if ( Vector3.Distance(currentPos, this.transform.position) & StepDistance)
GameObject Tmpobj = Instantiate(spehere, currentPos,Quaternion.identity) as GameO
currentPos = transform.
Destroy(Tmpobj, 0.3f);
}12345678910111213141516171819202122232425262728123456789101112131415161718192021222324252627286. 结果
在键盘上按下S键后,就可以挥动手柄来测试结果了。结果会实时在头盔中文字提示。
基本在正常速度下,都可以识别出来。
识别出来的结果还是通知来实现。若需要在根据结果来操作,只需要简单的订阅消息就可以了。是不是很简单。
三、识别代码解析
using UnityE
using System.C
using SLQJ;
using System.Collections.G
using UnityEngine.UI;
主要功能:
1.实现8中不同方向上的姿势识别
2.实现输入矢量来判断是否完成对应路线。
注意:每次只能识别一个姿势,需要等识别完毕,才能下一个。
@cartzhang
public enum GestureType:int
Left_Right,
LeftDown_RightUp,
RightDown_LeftUp,
Right_Left,
RightUp_LeftDown,
LeftUp_RightDown
public partial class GuestureJudge : MonoBehaviour
public Text showS
private bool isStartRecongnize = false;
[Header("挥动需要超过的距离 default 0.8")]
public float RecongnizeMinStepDistance = 0.8f;
[Header("数据跟踪的最短距离 default 0.08")]
public float addListMinStepDist = 0.08f;
[Header("检测周期时间,default 0.15")]
public float stepTime = 0.15f;
[Header("检测角度的最小冗余")]
[Range(5,15)]
public float MaxAnlgeToConfirm = 15f;
int arrowLayer = 10;
int layerM
int step = 0;
float currentStepT
开始检测标志
private bool bStartCheck = false;
private bool bOutputResult = false;
private GestureType gestureType = GestureType.N
private Camera mainC
void Start()
arrowLayer = 10;
layerMask = 1 && arrowL
currentStepTime = stepT
isStartRecongnize = false;
bOutputResult = false;
gestureType = GestureType.N
NotificationManager.Instance.Subscribe(NotificationType.Gesture_Recongnize.ToString(), GestureRecongnize);
StartUnderEditorTest();
mainCamera = Camera.
void Update()
UpdateUnderEditor();
#if UNITY_EDITOR
Debug.DrawRay(transform.position, transform.forward, Color.red);
CheckGestureByRay();
CheckGetsturebyCoordinate();
void GestureRecongnize(MessageObject obj)
object[] objArray = (object[])obj.MsgV
StartCoroutine(RecongnizeGetsture(Vector3.zero,(float)objArray[1]));
IEnumerator RecongnizeGetsture(Vector3 getstureVec, float TimeToDectect)
Debug.Log("start recongnize");
bOutputResult = false;
gestureType = GestureType.N
bStartCheck = true;
currentStepTime = stepT
while (TimeToDectect & 0)
if (bOutputResult || gestureType != GestureType.None)
Debug.Log("jump out while");
#if !UNITY_EDITOR
TimeToDectect = 0;
yield return null;
TimeToDectect -= Time.deltaT
bStartCheck = false;
Debug.Log("begin notify");
NotificationManager.Instance.Notify(
NotificationType.Gesture_Recongnize_Result.ToString(), bOutputResult);
NotificationManager.Instance.Notify(
NotificationType.Gesture_Recongnize_Result.ToString(), gestureType);
射线来检测碰撞体标签
private void CheckGestureByRay()
if (!bStartCheck)
currentStepTime -= Time.deltaT
if (currentStepTime &= 0)
currentStepTime = stepT
if (Physics.Raycast(transform.position, transform.forward, out hit, 6f, layerMask))
if (hit.collider.tag == "ArrowA")
Debug.Log("collison A");
if (hit.collider.tag == "ArrowB" && step == 1)
Debug.Log("collison B");
bOutputResult = true;
bStartCheck = false;
Test by use coordinate
每隔一帧采样数据,然后在时间间隔内
private bool bInitialOnce = false;
private int linkListMaxL
private List&Vector3& recordPosL
private List&Vector3& recordWorldToViewPosL
private Vector3[] SamplePos = new Vector3[3];
private int UpdateLenToCheck = 5;
private int iNewAddCount = 0;
private void CheckGetsturebyCoordinate()
if (!bStartCheck)
Vector3 currentRecordPos = transform.
Vector3 currentWVPPos = mainCamera.WorldToViewportPoint(currentRecordPos);
gestureType = GestureType.N
if (!bInitialOnce)
bInitialOnce = true;
linkListMaxLength = (int)(RecongnizeMinStepDistance / addListMinStepDist);
linkListMaxLength = linkListMaxLength & 5 ? 5 : linkListMaxL
recordPosList = new List&Vector3&(linkListMaxLength);
recordWorldToViewPosList = new List&Vector3&(linkListMaxLength);
recordPosList.Add(currentRecordPos);
recordWorldToViewPosList.Add(currentWVPPos);
UpdateLenToCheck = (int)(linkListMaxLength * 0.4f);
iNewAddCount = 0;
if (Vector3.Distance(recordPosList[recordPosList.Count - 1], currentRecordPos) & addListMinStepDist)
recordPosList.Add(currentRecordPos);
recordWorldToViewPosList.Add(currentWVPPos);
iNewAddCount++;
int currentListLen = recordPosList.C
if (currentListLen &= linkListMaxLength)
if (iNewAddCount & UpdateLenToCheck)
iNewAddCount = 0;
if (Vector3.Distance(recordPosList[0], recordPosList[currentListLen - 1]) & RecongnizeMinStepDistance * 0.3f)
int middleIndex = currentListLen && 1;
SamplePos[0] = (middleIndex &= 3) ? recordWorldToViewPosList[0]:
(recordWorldToViewPosList[0] + recordWorldToViewPosList[1] + recordWorldToViewPosList[2])/3;
SamplePos[1] = (middleIndex &= 3) ? recordWorldToViewPosList[middleIndex]:
(recordWorldToViewPosList[middleIndex-1] + recordWorldToViewPosList[middleIndex] + recordWorldToViewPosList[middleIndex+1]) / 3;
SamplePos[2] = (middleIndex &= 3) ? recordWorldToViewPosList[currentListLen - 1]:
(recordWorldToViewPosList[currentListLen - 1] + recordWorldToViewPosList[currentListLen - 2]) / 2;
CalcuolateDirection();
showState.text = gestureType.ToString();
if (gestureType != GestureType.None)
Debug.Log("current recongnize gesture is " + gestureType.ToString());
recordPosList.RemoveAt(0);
recordWorldToViewPosList.RemoveAt(0);
姿势判断。
private void CalcuolateDirection()
float anlge1 = GetAngleWithX(SamplePos[1] - SamplePos[0]);
float anlge2 = GetAngleWithX(SamplePos[2] - SamplePos[1]);
float stepAngle = 45;
int step = 0;
if ((anlge1 & MaxAnlgeToConfirm
+ stepAngle * step || (anlge1 & stepAngle * 8 - MaxAnlgeToConfirm && anlge1 & 8 * stepAngle)) &&
(anlge2 & MaxAnlgeToConfirm + stepAngle * step || (anlge2 & stepAngle * 8 - MaxAnlgeToConfirm && anlge2 & 8 * stepAngle))
gestureType = GestureType.Left_R
goto CDEND;
for (step = 1; step & 8; step++)
if ((anlge1 & stepAngle * step - MaxAnlgeToConfirm && anlge1 & stepAngle * step + MaxAnlgeToConfirm) &&
(anlge2 & stepAngle * step - MaxAnlgeToConfirm && anlge2 & stepAngle * step + MaxAnlgeToConfirm))
gestureType = (GestureType)(step + 1);
CDEND: return;
计算与X轴夹角
private float GetAngleWithX(Vector3 pos3D)
float angleOutput = Vector2.Angle(new Vector2(pos3D.x, pos3D.y), Vector2.right);
if (pos3D.y &= 0)
angleOutput = 360 - angleO
if (angleOutput &= 0)
return angleO
#endregion
动作识别的调用和结果返回。
public partial class GuestureJudge
void StartUnderEditorTest()
NotificationManager.Instance.Subscribe(
NotificationType.Gesture_Recongnize_Result.ToString(), GetRecongnizeResult);
void UpdateUnderEditor()
if (Input.GetKeyDown(KeyCode.S))
NotificationManager.Instance.Notify(
NotificationType.Gesture_Recongnize.ToString(),new Vector3(5,0,0),1000.0f);
#if UNITY_EDITOR
void OnDrawGizmosSelected()
Gizmos.color = Color.
Gizmos.DrawLine(transform.position, transform.position + (transform.forward * 100f));
void GetRecongnizeResult(MessageObject obj)
Debug.Log("recongnize output is " + obj.MsgValue);
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
识别的代码并算多,但也不少。我把类写成了两个部分,一部分就是常规的实现过程,另一部分就是辅助操作的代码,包括按下按键S开始识别运动方向,实时绘制射线,消息的通知和订阅等,结果的显示。
2. 方向枚举类
首先给八个方向定义了一个枚举类。
public enum GestureType:int
Left_Right,
LeftDown_RightUp,
RightDown_LeftUp,
Right_Left,
RightUp_LeftDown,
LeftUp_RightDown
}1234567891011121312345678910111213
这里说明,我实现了两种方向判断的,一种是用射线来判断的,对应函数CheckGestureByRay(),而另一种方法,是根据开头文章说的,根据路线方向通过矢量判断。
3. 射线判断方法及其优缺点
射线判断方法,使用了先判断射线射中的对象,通过层过滤和标签过滤来判断是否通过A点,然后在通过B点,这里就返回了。
优点是,几乎可以识别相机平面的所有方向,不在意朝向和位置,只要碰撞盒对就没有问题。
缺点就是,需设置层和标签。还有就是移动速度也不能过高,因为他会来不及计算或穿透过碰撞体,也可能会发生的。
说明,这个方法在的demo场景中并没有展示。有需要的可以找我或自己也可以根据代码稍微设置下tag和Layer,几乎无难度。
4. 路径跟踪计算及其优缺点
路径跟踪计算,根据记录来判断有限长度序列中的点,判断与X轴
优点是,可以屏蔽转向中,不会误识别成功。计算量其实也不大,效率也可以。可以根据需要随时调节参数,得到想要的结果。
缺点:算法需要转换为相机矩阵下的平面,因为手柄在移动过程中,相机也在移动,造成数据点在不同坐标平面下,可能会造成误识别。若每个点都计算在当前下,在整体计算过程中,就会得到记录的坐标点大家都不在一个坐标下生成的尴尬情况,这样更不能保证是否精确了。(希望大家有好的方法或想法,还请不吝指教。)
还有就是在代码中
姿势判断。
private void CalcuolateDirection()
123456123456
里面使用了很多人不太乐意的goto。其实,我大部分或说绝大部分时间都不希望这样用的,但是这里觉得可以用一些。
四、源码地址
源码地址:
整个工程包下载地址:
图片地址:
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!

我要回帖

更多关于 htc vive 手柄按键 的文章

 

随机推荐