HTC Vive开发笔记之手柄震动
手柄震动的代码SteamVR_Controller脚本的最上面的注释里面就有说明,其实也很简单
// Example usage:
//这个栗子是左手柄震动 右手震动只需把Leftmost换成Rightmost即可
// var deviceIndex = SteamVR_Controller.GetDeviceIndex(SteamVR_Controller.DeviceRelation.Leftmost);
// if (deviceIndex != -1 && SteamVR_Controller.Input(deviceIndex).GetPressDown(SteamVR_Controller.ButtonMask.Trigger))
// SteamVR_Controller.Input(deviceIndex).TriggerHapticPulse(1000);
//
//============================================================================= using UnityEngine;
using Valve.VR; /// <summary>
/// 手柄
/// </summary>
public class SteamVR_Controller
{
//按钮
public class ButtonMask
{
public const ulong System = (1ul << (int)EVRButtonId.k_EButton_System); // reserved 为Steam系统保留,用来调出Steam系统菜单
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);
} //设备
public class Device
{
public Device(uint i) { index = i; }
public uint index { get; private set; } public bool valid { get; private set; }
public bool connected { get { Update(); return pose.bDeviceIsConnected; } }
public bool hasTracking { get { Update(); return pose.bPoseIsValid; } } public bool outOfRange { get { Update(); return pose.eTrackingResult == ETrackingResult.Running_OutOfRange || pose.eTrackingResult == ETrackingResult.Calibrating_OutOfRange; } }
public bool calibrating { get { Update(); return pose.eTrackingResult == ETrackingResult.Calibrating_InProgress || pose.eTrackingResult == ETrackingResult.Calibrating_OutOfRange; } }
public bool uninitialized { get { Update(); return pose.eTrackingResult == ETrackingResult.Uninitialized; } } // These values are only accurate for the last controller state change (e.g. trigger release), and by definition, will always lag behind
// the predicted visual poses that drive SteamVR_TrackedObjects since they are sync'd to the input timestamp that caused them to update.
//这些值只在最近状态发生改变的才准确(例如 释放扳机),通过定义,将会总是在预测视觉动作(这个预测的信息用来驱动SteamVR_TrackedObjects)之后延迟,因为他们是和输入的时间戳同步更新的 public SteamVR_Utils.RigidTransform transform { get { Update(); return new SteamVR_Utils.RigidTransform(pose.mDeviceToAbsoluteTracking); } }
public Vector3 velocity { get { Update(); return new Vector3(pose.vVelocity.v0, pose.vVelocity.v1, -pose.vVelocity.v2); } }
public Vector3 angularVelocity { get { Update(); return new Vector3(-pose.vAngularVelocity.v0, -pose.vAngularVelocity.v1, pose.vAngularVelocity.v2); } } //获取状态 之前的状态 动作
public VRControllerState_t GetState() { Update(); return state; }
public VRControllerState_t GetPrevState() { Update(); return prevState; }
public TrackedDevicePose_t GetPose() { Update(); return pose; } VRControllerState_t state, prevState;
TrackedDevicePose_t pose;
int prevFrameCount = -;
public void Update()
{
if (Time.frameCount != prevFrameCount)
{
prevFrameCount = Time.frameCount;
prevState = state; var system = OpenVR.System;
if (system != null)
{
valid = system.GetControllerStateWithPose(SteamVR_Render.instance.trackingSpace, index, ref state, ref pose);
UpdateHairTrigger();
}
}
} //长按 按下 抬起 两种参数buttonMask buttonId
public bool GetPress(ulong buttonMask) { Update(); return (state.ulButtonPressed & buttonMask) != ; }
public bool GetPressDown(ulong buttonMask) { Update(); return (state.ulButtonPressed & buttonMask) != && (prevState.ulButtonPressed & buttonMask) == ; }
public bool GetPressUp(ulong buttonMask) { Update(); return (state.ulButtonPressed & buttonMask) == && (prevState.ulButtonPressed & buttonMask) != ; } public bool GetPress(EVRButtonId buttonId) { return GetPress(1ul << (int)buttonId); }
public bool GetPressDown(EVRButtonId buttonId) { return GetPressDown(1ul << (int)buttonId); }
public bool GetPressUp(EVRButtonId buttonId) { return GetPressUp(1ul << (int)buttonId); } //触摸 按下 抬起
public bool GetTouch(ulong buttonMask) { Update(); return (state.ulButtonTouched & buttonMask) != ; }
public bool GetTouchDown(ulong buttonMask) { Update(); return (state.ulButtonTouched & buttonMask) != && (prevState.ulButtonTouched & buttonMask) == ; }
public bool GetTouchUp(ulong buttonMask) { Update(); return (state.ulButtonTouched & buttonMask) == && (prevState.ulButtonTouched & buttonMask) != ; } public bool GetTouch(EVRButtonId buttonId) { return GetTouch(1ul << (int)buttonId); }
public bool GetTouchDown(EVRButtonId buttonId) { return GetTouchDown(1ul << (int)buttonId); }
public bool GetTouchUp(EVRButtonId buttonId) { return GetTouchUp(1ul << (int)buttonId); } //获取轴心 此处是用来返回手指在触摸板Touchpad上的位置
public Vector2 GetAxis(EVRButtonId buttonId = EVRButtonId.k_EButton_SteamVR_Touchpad)
{
Update();
var axisId = (uint)buttonId - (uint)EVRButtonId.k_EButton_Axis0;
switch (axisId)
{
case : return new Vector2(state.rAxis0.x, state.rAxis0.y);
case : return new Vector2(state.rAxis1.x, state.rAxis1.y);
case : return new Vector2(state.rAxis2.x, state.rAxis2.y);
case : return new Vector2(state.rAxis3.x, state.rAxis3.y);
case : return new Vector2(state.rAxis4.x, state.rAxis4.y);
}
return Vector2.zero;
} //上面提到的震动方法
public void TriggerHapticPulse(ushort durationMicroSec = , EVRButtonId buttonId = EVRButtonId.k_EButton_SteamVR_Touchpad)
{
var system = OpenVR.System;
if (system != null)
{
var axisId = (uint)buttonId - (uint)EVRButtonId.k_EButton_Axis0;
system.TriggerHapticPulse(index, axisId, (char)durationMicroSec);
}
} //扳机扣下或释放的量才可以改变状态
public float hairTriggerDelta = 0.1f; // amount trigger must be pulled or released to change state
float hairTriggerLimit;
bool hairTriggerState, hairTriggerPrevState;
/// <summary>
/// 更新扳机状态
/// </summary>
void UpdateHairTrigger()
{
hairTriggerPrevState = hairTriggerState;
var value = state.rAxis1.x; // trigger
if (hairTriggerState)
{
if (value < hairTriggerLimit - hairTriggerDelta || value <= 0.0f)
hairTriggerState = false;
}
else
{
if (value > hairTriggerLimit + hairTriggerDelta || value >= 1.0f)
hairTriggerState = true;
}
hairTriggerLimit = hairTriggerState ? Mathf.Max(hairTriggerLimit, value) : Mathf.Min(hairTriggerLimit, value);
} public bool GetHairTrigger() { Update(); return hairTriggerState; }
public bool GetHairTriggerDown() { Update(); return hairTriggerState && !hairTriggerPrevState; }
public bool GetHairTriggerUp() { Update(); return !hairTriggerState && hairTriggerPrevState; }
} private static Device[] devices; /// <summary>
/// 输入的具体设备
/// </summary>
/// <param name="deviceIndex">Device index.</param>
public static Device Input(int deviceIndex)
{
if (devices == null)
{
devices = new Device[OpenVR.k_unMaxTrackedDeviceCount];
for (uint i = ; i < devices.Length; i++)
devices[i] = new Device(i);
} return devices[deviceIndex];
} public static void Update()
{
for (int i = ; i < OpenVR.k_unMaxTrackedDeviceCount; i++)
Input(i).Update();
} // This helper can be used in a variety of ways. Beware that indices may change
// as new devices are dynamically added or removed, controllers are physically
// swapped between hands, arms crossed, etc.
//这个枚举帮手用很多用法.注意索引也许会因为动态的新增或者移除而改变
//或者控制器物理上的在双手/双臂之间交换,等等
public enum DeviceRelation
{
First,
// radially
Leftmost,
Rightmost,
// distance - also see vr.hmd.GetSortedTrackedDeviceIndicesOfClass
FarthestLeft,
FarthestRight,
} /// <summary>
/// 获取设备的索引
/// </summary>
/// <returns>The device index.</returns>
/// <param name="relation">Relation.</param>
/// <param name="deviceClass">Device class.</param>
/// <param name="relativeTo">Relative to.</param>
public static int GetDeviceIndex(DeviceRelation relation,
ETrackedDeviceClass deviceClass = ETrackedDeviceClass.Controller,
int relativeTo = (int)OpenVR.k_unTrackedDeviceIndex_Hmd) // use -1 for absolute tracking space
{
var result = -; var invXform = ((uint)relativeTo < OpenVR.k_unMaxTrackedDeviceCount) ?
Input(relativeTo).transform.GetInverse() : SteamVR_Utils.RigidTransform.identity; var system = OpenVR.System;
if (system == null)
return result; var best = -float.MaxValue;
for (int i = ; i < OpenVR.k_unMaxTrackedDeviceCount; i++)
{
if (i == relativeTo || system.GetTrackedDeviceClass((uint)i) != deviceClass)
continue; var device = Input(i);
if (!device.connected)
continue; if (relation == DeviceRelation.First)
return i; float score; var pos = invXform * device.transform.pos;
if (relation == DeviceRelation.FarthestRight)
{
score = pos.x;
}
else if (relation == DeviceRelation.FarthestLeft)
{
score = -pos.x;
}
else
{
var dir = new Vector3(pos.x, 0.0f, pos.z).normalized;
var dot = Vector3.Dot(dir, Vector3.forward);
var cross = Vector3.Cross(dir, Vector3.forward);
if (relation == DeviceRelation.Leftmost)
{
score = (cross.y > 0.0f) ? 2.0f - dot : dot;
}
else
{
score = (cross.y < 0.0f) ? 2.0f - dot : dot;
}
} if (score > best)
{
result = i;
best = score;
}
} return result;
}
}
另外分享一个别人的关于手柄震动的教程,比较详细~~
新建yzx_controller脚本,挂在手柄上即可
一、 手柄震动一下(真的只震动一下,也许不注意都感受不到!)
using UnityEngine;
using System.Collections; public class yzx_controller : MonoBehaviour
{ SteamVR_TrackedObject Hand;
SteamVR_Controller.Device device; // Use this for initialization
void Start () {
Hand = GetComponent<SteamVR_TrackedObject>(); //获得SteamVR_ TrackedObject组件
} // Update is called once per frame
void Update () { if (Hand.isValid)
{
//防止Start函数没加载成功,保证SteamVR_ TrackedObject组件获取成功!
Hand = GetComponent<SteamVR_TrackedObject>();
}
//根据index,获得手柄
device = SteamVR_Controller.Input((int)Hand.index); //如果手柄的Trigger键被按下了
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Trigger))
{
Debug.Log("Trigger is pressed!"); //控制台输出Trigger is pressed!
device.TriggerHapticPulse(); //手柄震动函数,500代表振幅,是一个ushort类型
} }
运行程序,扣一下Trigger键,咦,好像不对劲,都没感觉发生了什么。也许你会怀疑人生,是不是都没有捕捉到Trigger键被按下的事件?
No,No,No,明明控制台打印了Trigger is pressed !
这是为什么?……
因为,手柄只震动了一下下,你根本感觉不到。当然,你也可以修改这句代码device.TriggerHapticPulse(500); 将参数500调成1000,甚至更大(数值越大,振幅越大), 然而,震感还是太低了,因为,持续时间太短了……
二、手柄持续震动(这次,真的很有震感了……)
自然想到,如果要让手柄有震感,那么震动持续的时间一定要有保证!!!
下面的代码中,你可以随便修改代码StartCoroutine(“Shock”,0.5f) 的第二个参数(代表震动持续时间),0.5f 代表手柄持续震动0.5s,想震多久就震多久……Cool !!!
我的想法:就是通过协程去执行手柄震动,然后通过Invoke函数来决定延迟时间,即控制手柄震动的持续时间。
全面修改 yzx_controller.cs脚本,代码如下:
using UnityEngine;
using System.Collections; public class yzx_controller : MonoBehaviour
{
SteamVR_TrackedObject Hand;
SteamVR_Controller.Device device; bool IsShock = false; //布尔型变量IsShock // Use this for initialization
void Start ()
{
Hand = GetComponent<SteamVR_TrackedObject>(); //获得SteamVR_ TrackedObject组件
} // Update is called once per frame
void Update ()
{ //防止Start函数没加载成功,保证SteamVR_ TrackedObject组件获取成功!
if (Hand.isValid)
{
Hand = GetComponent<SteamVR_TrackedObject>();
}
device = SteamVR_Controller.Input((int)Hand.index); //根据index,获得手柄
//如果手柄的Trigger键被按下了
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Trigger))
{ IsShock = false; //每次按下,IsShock为false,才能保证手柄震动
StartCoroutine("Shock",0.5f); //开启协程Shock(),第二个参数0.5f 即为协程Shock()的形参
} } //定义了一个协程 IEnumerator Shock(float durationTime) { //Invoke函数,表示durationTime秒后,执行StopShock函数;
Invoke("StopShock", durationTime); //协程一直使得手柄产生震动,直到布尔型变量IsShock为false;
while (!IsShock)
{
device.TriggerHapticPulse(); yield return new WaitForEndOfFrame(); } } void StopShock()
{
IsShock = true; //关闭手柄的震动
} }
运行程序,Amazing!手柄真的真的震动起来了,而且可以随意调节震动的持续时间, So cool ……
HTC Vive开发笔记之手柄震动的更多相关文章
- HTC Vive开发笔记之SteamVR插件集成
重要组件 SteamVR_Camera VR摄像机,主要功能是将Unity摄像机的画面进行变化,形成Vive中的成像画面 使用方法: l 在任一个摄像机上增加脚本 l 点击Expand按钮 完成以上操 ...
- HTC Vive开发笔记之手柄控制
怎么安装设备,配置环境我就不说了,自行百度,教程很多也很简单.接下来说下Vive手柄的控制. 手柄是HTC Vive的重要交互手段,我们通过第一个图片应该对其有一个直观的了解了,总共是九个按钮: 第一 ...
- HTC Vive开发笔记之UI Guideline
本文转自HTC官方论坛,原址https://www.htcvive.com/cn/forum/chat.php?mod=viewthread&tid=1641&extra=page=1 ...
- HTC vive开发:关于手柄按键
一.关于左右手柄的对应关系 两个手柄和SteamVR_TrackedObject.EIndex是对应的,一个是EIndex.Device2,另一个是EIndex.Device3(有编号的那个) 在场景 ...
- Unity的HTC VIVE SDK研究(手柄按键功能的研究,比较详细)
http://blog.csdn.net/ystistheking/article/details/51553237 想交流的朋友我们可以微博互粉,我的微博黑石铸造厂厂长 ,缺粉丝啊 .....求粉求 ...
- unity3D HTC VIVE开发-物体高亮功能实现
在VR开发时,有时需要用到物体高亮的功能.这里使用Highlighting System v3.0.1.unitypackage插件实现. Highlighting System v3.0.1的介绍访 ...
- osgMulitiplerendertargets sample 中fbo使用【HTC VIVE开发中应用】
osgmultiplerendertargets.cpp ...................................... // now create the camera to do t ...
- Unity 5.4大赞:HTC Vive经典The lab渲染器开源
HTC Vive提供了一个不错的免费VR demo,最近1周仔细体验了一番. 仔细看了其安装文件,竟然是Unity 5.4beta版本(通过查log,知道Valve公司用的是最新的5.4.0b11版本 ...
- 用Unity开发HTC VIVE——手柄控制篇
写这篇文章的原因主要是因为现在虚拟现实非常的火爆但目前主流的虚拟现实设备(HTC VIVE)的教程却少的可怜,这个我深有体会.所以,我想将我平时开发中遇到的问题以及解决方法记录下来,分享给大家,若其中 ...
随机推荐
- contextloaderlistener
http://blog.csdn.net/c5153000/article/details/6234207 作用:在启动Web容器时,自动装配Spring applicationContext.xml ...
- Java使用ZXing生成二维码条形码
一.下载Zxingjar包 本实例使用的是 zxing3.2.0的版本 下载地址 http://pan.baidu.com/s/1gdH7PzP 说明:本实例使用的3.2.0版本已经使用的java7 ...
- Windows下Apache的优化
(1)首选查看apache的工作模式 windows下的查看apache的工作模式命令: httpd -l 如果列出mod_win32.c,则表示是 win32.c 工作方式. 列出的全部内容如下所示 ...
- WCF初探-13:WCF客户端为双工服务创建回调对象
前言: 在WCF初探-5:WCF消息交换模式之双工通讯(Duplex)博文中,我讲解了双工通信服务的一个应用场景,即订阅和发布模式,这一篇,我将通过一个消息发送的例子讲解一下WCF客户端如何为双工服务 ...
- this kernel requires an x86-64 CPU, but only detected an i686 CPU. unable to boot - please ues a ker
http://blog.csdn.net/xiao_cs/article/details/7728529 this kernel requires an x86-64 CPU, but only de ...
- 关于Elasticsearch单个索引文档最大数量问题
因为ElasticSearch是一个基于Lucene的搜索服务器.Lucene的索引有个难以克服的限制,导致Elasticsearch的单个分片存在最大文档数量限制,一个索引分片的最大文档数量是20亿 ...
- js面向对象组件
1.包装对象 <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" ...
- Css中常用中文字体的Unicode编码对照
在网页制作中,最常用的恐怕是字体属性了,在调整页面兼容的时候,也常常发现字体名称的原因导致不兼容或乱码,下面给出几种常用字体的ucicode编码对照,方便使用. 宋体 SimSun \5B8B\4F5 ...
- HiveQL(HiveSQL)跟普通SQL最大区别一直使用PIG,而今也需要兼顾HIVE
HiveQL(Hive SQL)跟普通SQL最大区别 一直使用PIG,而今也需要兼顾HIVE.网上搜了点资料,感觉挺有用,这里翻译过来.翻译估计不太准确,待自己熟悉HIVE后再慢慢总结. * No t ...
- MVC记录
MVC这三层分别要完成哪些工作呢? 1.M层 模型(更多的是数据库模型) (1)创建数据库.创建相应的表 (2)完成针对数据库各个表的增.删.改.查的操作类 (3)映射数据库各个表的实体类(这个实体类 ...