Oculus的Touch, HTC Vive的Controller, PSVR的PS Move, 三家一线VR硬件都在给大家传达一个信息: VR下能够模拟双手的体感控制器是一个趋势. 在VR游戏中, 一旦有了双手, 这就意味着不光能看了…..如果说之前的VR游戏只是输出方式(显示器)发生了变化, 那现在有了个双手, 输入方式也发生了变化, 这对游戏来说是一个革命性的改变, 是完全可以改变用户体验的. 由此我们也看到了代表未来的一些VR应用开始出现: 如空间绘画Tilt Brush, VR雕塑Oculus Medium等. 从游戏玩法的角度, 如果能把传统的玩法跟双手的交互方式相结合, 这就是一个创新, 可以让VR游戏不仅仅是好看, 从而变得开始好玩.
这种双持的体感控制器, 在UE4中统称为MotionController, 在Unity中嘛(我们都是野孩子). 有了双手, 第一件想干事是什么? (嗯, 我指的不是摸) 是抓东西, 扔东西. 对于基于Motion Controller的操作方式来说, 是最最基本的一个功能了. 然而, 这个看似简单的功能, 却有很多问题, 没有办法做到非常完美.
不就是把物体挂到手上吗? 有那么困难? 我先来分析一下实现方式:
这也是最常见的实现方法, 直接把Hand做为父结点, 把物体当成子级挂上去
每帧更新物体的位置(和朝向), 让它跟Hand保持一致. 相对于方法1需要在移动时考虑碰撞, 比如在UE4中就是设置Sweep=true
每帧更新物体的速度(角速度), 让它不断地追赶Hand. 这个方法的缺点是有一帧延迟, 移动得快了是肉眼可见物体与手脱离的.
直接把物体和手的碰撞体用Constraint进行连接. 看上去与方法1很像, 区别是一个是场景逻辑层面的, 一个物理引擎层面的.
因为双手是虚拟的, 物体也是虚拟的, 所以想完全模拟出现实中一模一样的体验是不可能的(至少现阶段不行). 上述几种方法也不是都不能用, 只是各自都有其不完美的地方. 下面挨个问题来说:
除了悬浮的物体, 一般是都有重量的. 但是拿到手上后, 这个受力是需要解除的, 不然会不停往下掉. 一般都是抓起来后就关掉重力影响, 放开时再恢复, 这个大家应该都有考虑到.
方法2的实现在扔出去后其实是没有继承手部的速度的, 所以需要自行对Rigidbody设置速度(和角速度). 方法1对于不同引擎实现机制不同, 也会有类似的问题.
当我们手上没抓东西时, 让手插入静态场景模型(比如墙壁), 怎么处理? 一种做法是让手保持与现实中的位置一至, 一种做法是让手留在碰撞的地方不动. 前一种做法更常见, 因为可以有比较好的沉浸感, 不过也有人会有异议, 下文都是假设以前一种做法为基础.
当我们手上拿着东西时, 让手上的物体插入墙壁, 这时候怎么处理? 有人说也可以让它像手一样穿过墙壁呀, 但是如果这么做了的话, 这时松开手, 这个物体就卡在墙上了, 或者被弹飞(物理引擎的一些问题). 所以正确的做法一般是让手上的物体留在墙面上, 手穿过去, 这时松手的话, 物体自然掉落.
方法1和方法4都有穿插的问题. 方法3会有不断碰撞造成的抖动问题, 可以临时禁用弹性系数解决.
假设物体A和物体B都是可以拿起来的动态物理对象, 手拿起物体A, 去推物体B. 方法2物体A会停在物体B上, 物体B不会动. 方法1和方法4可以把物体B推动. 方法3如果物体A质量远小于物体B, 是推不动的, 所以这是最能符合我们期望的结果.
常见的应用场景是手拿球拍去击球. 方法1在速度非常快的情况下会击不出球, 因为前一帧在球前, 后一帧就跑到球后面去了. 方法2球拍会停在与球接触的地方. 方法3和方法4可以符合预期.
比如一个转盘, 只能绕一个轴旋转. 手持一个物体去推动这个转盘.
方法1: 转盘会被推到偏离转轴
方法2: 物体停在与转盘接触的位置
方法3: 物体停在与转盘接触的位置, 转盘会正常转动, 不过也会出现抖动问题
方法4: 物体会与转盘穿插, 但转盘会正常转动
空手直接去抓转盘进行交互是不行的, 可以参考NVR(参考资料1)的实现, 把抓取行为改为对转盘释加力进行转动.
如果想模拟出提起物体时不同重量物体的表现 , 可以通过施加力的方式来模拟出物体与手之间的相对移动, 通过速度快慢表现出不同物体的重量. 见参考资料2
不同材质, 不同重量的物体, 可以通过控制器的振动频率和振幅来进行模拟.
有些物体我们希望任意位置都可以抓住, 比如球, 花瓶, 玩具等. 有些物体我们希望手拿起来就在把手位置, 比如球拍, 手枪等. 这种可以在物体上设置挂点解决.
待继…