在物理实验室模块,为了体现虚拟现实的特性,充实功能,打算实现kinect在VR环境中的模拟。通过用户的手势,动作;得到一个返回值,用来触发某些事件。即模拟kinect的运作方式,处理图像中人体的运动手势,触发相应的事件。
通过手柄的位置的位移来触发事件:
声明SteamVR_TrackedObject对象,根据Steam vr sdk中拓展代码,构造手柄按钮事件。调用这个类中的手柄对象的方法,来实现左右手柄的监听功能,获取手柄位置等信息。
通过VRTK_DeviceFinder类,寻找有手柄,返回位置等信息,具体实现:
RightController = VRTK_DeviceFinder.GetControllerRightHand ();
var device = SteamVR_Controller.Input((int)trackedObjec.index);
在start函数里面赋值手柄的位置。
在update中,当此模块运行,开始检测时。当按下手柄的trigger记录一个手柄的位置,当trigger抬起时,记录一个手柄的位置。得到两个vector3属性的值。可以计算这两个值分别在x,y,z方向上的分量。
通过在三个坐标轴方向上的分量,可以判断此次手柄的移动轨迹是朝向什么方向的,通过不同的方向触发事件。
void Start () { RightController = VRTK_DeviceFinder.GetControllerRightHand (); preConPosition = ConPosition = RightController.transform.position; } // Update is called once per frame void Update () { var device = SteamVR_Controller.Input((int)trackedObjec.index); while(sk.isRun == true){ if(device.GetTouchDown(SteamVR_Controller.ButtonMask.Trigger)){ IsSelect = true; preConPosition = RightController.transform.position; } if(device.GetTouchUp(SteamVR_Controller.ButtonMask.Trigger) && IsSelect){ ConPosition = RightController.transform.position; IsSelect = false; } gesture = Calculate (preConPosition,ConPosition); preConPosition = ConPosition = new Vector3(0,0,0); } } int Calculate(Vector3 preC,Vector3 C){ float ResultX = C.x - preC.x; float ResultY = C.y - preC.y; float ResultZ = C.z - preC.z; }
但这种方式有很大的局限性,只能将位移看作是一条直线,没办法处理更复杂的手势情况。
下面提出的模拟方法是通过设置在指定位置一定数量的trigger,通过手柄的移动,触发各个trigger。此时我们可以得到手柄移动的路径,通过这种路径的形式来记录用户的手势运动,触发事件。
目前做了一个demo,还没在VR中实现。demo中,我设置了六个cube作为trigger,给予相应的标签。并赋予不同的编号。
sphere作为手柄,通过OnTriggerEnter的方式检测碰撞事件。
public List<int> paths = new List<int> ();
sphere的脚本上,定义了一个动态数组,用来存储路径。每当sphere与一个trigger触发时,记录此trigger的标号。当按下某一个键位,输出数组中存储的trigger路径。
我是通过将路径值转化为string类型,通过if语句与实现定义的事件的出发路径做判断,以达到触发事件的目的。
string numListToString(List<int> temp){ string str = ""; foreach (int n in temp) str += n + " "; return str; }
此种方式,可以比较灵活的设置trigger的位置,根据精度设置数量;同时在交互的过程中,可以记录更复杂的路径信息,做更多的手势。
void Update () { if(Input.GetKeyDown(KeyCode.Space)){ string path1 = numListToString (paths); Debug.Log (path1); int kind = compare (path1); if(kind == 1){ Debug.Log ("触发事件1"); } reset (paths); } }