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 = -1;
        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) != 0; }
        public bool GetPressDown(ulong buttonMask) { Update(); return (state.ulButtonPressed & buttonMask) != 0 && (prevState.ulButtonPressed & buttonMask) == 0; }
        public bool GetPressUp(ulong buttonMask) { Update(); return (state.ulButtonPressed & buttonMask) == 0 && (prevState.ulButtonPressed & buttonMask) != 0; }

        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) != 0; }
        public bool GetTouchDown(ulong buttonMask) { Update(); return (state.ulButtonTouched & buttonMask) != 0 && (prevState.ulButtonTouched & buttonMask) == 0; }
        public bool GetTouchUp(ulong buttonMask) { Update(); return (state.ulButtonTouched & buttonMask) == 0 && (prevState.ulButtonTouched & buttonMask) != 0; }

        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 0: return new Vector2(state.rAxis0.x, state.rAxis0.y);
                case 1: return new Vector2(state.rAxis1.x, state.rAxis1.y);
                case 2: return new Vector2(state.rAxis2.x, state.rAxis2.y);
                case 3: return new Vector2(state.rAxis3.x, state.rAxis3.y);
                case 4: return new Vector2(state.rAxis4.x, state.rAxis4.y);
            }
            return Vector2.zero;
        }

        //上面提到的震动方法
        public void TriggerHapticPulse(ushort durationMicroSec = 500, 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 = 0; i < devices.Length; i++)
                devices[i] = new Device(i);
        }

        return devices[deviceIndex];
    }

    public static void Update()
    {
        for (int i = 0; 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 = -1;

        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 = 0; 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); //手柄震动函数,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(500);

            yield return new WaitForEndOfFrame();

        }

    }

    void StopShock()
    {
        IsShock = true; //关闭手柄的震动
    }

}

运行程序,Amazing!手柄真的真的震动起来了,而且可以随意调节震动的持续时间, So cool ……

时间: 2024-10-15 00:22:58

HTC Vive开发笔记之手柄震动的相关文章

HTC Vive开发笔记之手柄控制

怎么安装设备,配置环境我就不说了,自行百度,教程很多也很简单.接下来说下Vive手柄的控制. 手柄是HTC Vive的重要交互手段,我们通过第一个图片应该对其有一个直观的了解了,总共是九个按钮: 第一个是菜单按钮; 2,3,4,5分别对应的是Trackpad/Touchpad的上下左右,有时候对应的是XBox手柄的▲OX囗四个按钮或者摇杆; 6对应的是系统按钮/Steam; 7是Trigger/扳机,对应大多数FPS游戏里面的枪械的Shoot/Fire; 8对应的Grip/紧握在手柄的左右两侧各

HTC Vive开发笔记之SteamVR插件集成

重要组件 SteamVR_Camera VR摄像机,主要功能是将Unity摄像机的画面进行变化,形成Vive中的成像画面 使用方法: l 在任一个摄像机上增加脚本 l 点击Expand按钮 完成以上操作后,原本的摄像机会变成如下结构 l Origin:位置 l Head:头部 l Eye:眼睛 l Ears:耳朵 至此,游戏中Vive中可以看到游戏画面,360度旋转查看游戏世界,在游戏世界中移动等 SteamVR_ControllerManager和SteamVR_TrackedObject 控

HTC Vive开发笔记之UI Guideline

本文转自HTC官方论坛,原址https://www.htcvive.com/cn/forum/chat.php?mod=viewthread&tid=1641&extra=page=1. 在过去,3D程序多数是游戏,非游戏的应用一般设计成2D程序.而在VR中几乎所有程序都是3D的(左右眼需要看到的不一样画面),所以开发VR程序和开发3D游戏很像,也可以使用Unity, Unreal等引擎.而VR开发的独特之处在于UI设计,如果还用之前的方案,用户使用的时候可能会觉得非常困惑甚至头晕.这篇文

HTC vive开发:关于手柄按键

一.关于左右手柄的对应关系 两个手柄和SteamVR_TrackedObject.EIndex是对应的,一个是EIndex.Device2,另一个是EIndex.Device3(有编号的那个) 在场景中手柄先后连入,先后激活的是Controller(right).Controller(left),并添加SteamVR_TrackedObject组件 二.手柄按键 1 - 菜单键 6 - 系统键(按下后手柄断开连接,再次按下手柄再次连接上) 7 - 扳机键 8 - 握持键 9 - 触摸板键 (1)

Unity的HTC VIVE SDK研究(手柄按键功能的研究,比较详细)

http://blog.csdn.net/ystistheking/article/details/51553237 想交流的朋友我们可以微博互粉,我的微博黑石铸造厂厂长 ,缺粉丝啊 .....求粉求粉 研究了几天htc vive的接口,总算是把基本的按键功能研究出来了,这里分享一下,一来当做笔记,二来也希望对大家有所帮助. 如何导入Steam_VR那个包什么的我就不说了,网上有几个前辈已经教了,蛮牛论坛啥的上面都有,这里只把比较详细的按键功能分享一下,不知啥高端的东西,也算一段时间劳动成果啦,

GJM:Unity开发HTC vive 三、远处拖动3D物体 【转载】

腾讯GAD 窗间风月 原文URL : http://gad.qq.com/article/detail/7192223 版权所有,禁止匿名转载:禁止商业使用:禁止个人使用. 在项目中会需要拖动远处的物体,这种要如何去实现,下面就给大家介绍下在Unity HTC vive开发中远处拖动3D物体的教程. 效果如下,手柄射线照射到3D物体的时候,可以通过Trigger按钮抓住物体并拖动 1.导入SDK:SteamVR Plugin和Vive Input Utility 2.删除场景中的默认摄像机,将C

Unity 5.4大赞:HTC Vive经典The lab渲染器开源

HTC Vive提供了一个不错的免费VR demo,最近1周仔细体验了一番. 仔细看了其安装文件,竟然是Unity 5.4beta版本(通过查log,知道Valve公司用的是最新的5.4.0b11版本开发的),的确令人信心大振: 要知道,某些创业公司为了打差异化竞争,提高技术门槛,对外称Unreal 4的画质比Unity 5优秀很多,这让很多在Unity技术栈下的公司有些郁闷–多年来Unity画质始终不如Unreal逼格高啊. The Lab 程序路径:Steam\steamapps\commo

Unity HTC VIVE手柄 按键说明

一.HTC VIVE手柄按键图说明 1 - 菜单键 6 - 系统键(按下后手柄断开连接,再次按下手柄再次连接上) 7 - 扳机键 8 - 握持键 9 - 触摸板键 二.按键的监听方式 1.按键监听方式一:(SteamVR的方式,封装了OpenVR) (1)点击触发:通过Device.GetPressDown / GetPressUp / GetPress获取按键事件 (2)触摸触发:通过device .GetTouchDown / GetTouchUp / GetTouch获取按键事件 2.按键

用Unity开发HTC VIVE——手柄控制篇

写这篇文章的原因主要是因为现在虚拟现实非常的火爆但目前主流的虚拟现实设备(HTC VIVE)的教程却少的可怜,这个我深有体会.所以,我想将我平时开发中遇到的问题以及解决方法记录下来,分享给大家,若其中有什么错误或者大家有什么更好的方案也请大家指出,大家互相学习,哈哈. 好了直接上代码. using UnityEngine; using System.Collections; public class shoubingkongzhi : MonoBehaviour { /// /// 手柄 ///