查看原文
其他

NewtonVR丨基于真实物理学的Vive VR游戏交互革新(中)

2016-06-15 陆于璇 Gad-腾讯游戏开发者平台
导读:因为本文篇幅比较长,我们将分成上中下(三篇)在GAD微信公众号里连续三天推送。
上篇回顾:NewtonVR丨基于真实物理学的Vive VR游戏交互革新(上)

物理法则的使用
我们最希望的系统是全物理的,在这样的系统之中,用控制器控制的物体都将保持非纯运动学状态,但是设计这样的系统也有巨大的挑战。
首先,如果我们仅仅通过运动学移动物体(包含了力,速度,加速度),那么我们应该使用什么概念,并且应该如何应用这个概念?
Unity给用户提供了以下几种选项:
1)我可以直接改变刚体的速度。Unity的文档并不推荐这么做,因为这样会忽略加速度,导致运动看起来并不自然。但是我们并不放弃使用这种方法的可能性。
2)我也可以通过AddForce()方法对一个刚体施加一个力或者力矩。通过选择ForceMode选项之后Unity可以应用力矢量:力(质量*加速度)、加速度(速度/时间)、速度(位置/时间)、冲量(质量*速度)第二,如果我们使用力,我们将如何测量并计算矢量?如果我们不能在每一帧得到符合玩家本意的大小和方向,那么游戏就不具有可玩性。
我们的解决方案
最后,让我们看看一种令人惊喜的解决方案吧!相比于直接给对象添加作用力,我们发现直接改变可交互对象的速度是模拟抓取物体的最佳办法,这种方法同时还可以使物体能够受到外部力的影响。

最初,我们设想在将力的模式设置为ForceMode的情况下,通过AddForce()方法来调整物体的位置和旋转角度。基矢量是交互状态下物体的位置矢量和手的位置矢量的差值,该矢量的方向始终指向手。
代码:protected void UpdateForceOnControl(VRHand hand){    Vector3 toHandPos = (hand.transform.position - this.transform.position);    AttachedRigidbody.AddForce(toHandPos * AttachedPositionMagic, ForceMode.Force);}采用这种方法的缺点在于矢量的大小非常小,这是因为玩家只能够捡起他们已经可以碰触到的物体。一般来说,物体会和手重合。我们选择对矢量做了一个乘法作为解决方案。但是事实上,我本人并不喜欢使用魔数,但在这个案例中,它是最快速有效的解决方案。
这也会带来一些我们并不期望的结果。物体会始终在手的附近飞行,但是重力会将物体往地面方向拉动,增大了手和物体的距离,直到距离足够大时,物品会被弹回手上。
然后,我们又尝试将ForceMode选为加速度模式,并应用力的作用。
代码:protected void UpdateForceOnControl(VRHand hand){    Vector3 force = hand.GetComponent<Rigidbody>().mass * this.GetComponent<VelocityEstimator>().GetAccelerationEstimate();    AttachedRigidbody.AddForce(force * AttachedPositionMagic, ForceMode.Acceleration);}
这种方法的问题在于:只有当控制器移动时,才会有力的作用。如果玩家移动的足够快,力就会足够大;如果玩家移动的足够慢,力就会足够小。
这样的结果是合理的,但是问题在于如果玩家完全不移动会怎么样呢?这种情况下,将会不施加任何力的作用,物体会在重力作用下简单的下坠。
为了进一步看看到底会有什么样的结果,我们决定尝试改变速度方向。矢量仍然是可交互对象和手的位置矢量的差值,但是我们不使用AddForce()施加其他力。
代码:PositionDelta = (AttachedBy.transform.position - InteractionPoint.position);this.Rigidbody.velocity = PositionDelta * AttachedPositionMagic * Time.fixedDeltaTime;
经证明,这种方法非常成功。被抓取的物体会快速移向控制器,并且会有一些延迟的跟随控制器的运动。当物体的位置和控制器的位置向匹配时,速度就会被设置为0.这样做就没有必要连续地施力,并且用额外的力去抵消那些力(它们会使得物体发生振动)。
所有的Unity GamObjects对象都拥有速度属性,并且一般来说它们的速度不能被直接修改,但是因为我们需要让进行交互的物体可以缓慢地移向玩家控制器并且在到达控制器处能够停止运动,修改物体的速度就变得有必要了。这也意味着物体可以被外部的力影响,但是只要控制器没有以比速度修改更快的速度移出交互触发距离以外,物体就会持续地向玩家靠近。
直接进行速度修改没有考虑质量的作用,所以是不符合现实的方式,但是对于玩家来说却可以有更完美的体验。玩家永远也不可能感受到虚拟物体的重量,而他们移动物体的速度完全由它们挥舞控制器的速度所决定。
四元数困境
旋转是一种四元数操作,但是Unity并没有进行四元数算术运算的操作,因此我们不能简单地采用(手旋转-物体旋转),并最终产生旋转的不同。另外一个问题是,角速度也是一个矢量,而非四元数,这意味着我们实际上必须计算出角速度。
我们对于旋转问题的解决方案来自于在角度坐标轴形式中表示四元数旋转(从初始方向转动到最终方向)。
我们知道只要知道两个方向四元数就可以通过将最终方向四元数乘以当前方向四元数的倒数计算出转动四元数(GameObject.transform.rotation是一个方向四元数)。(RotationDelta = AttachedHand.transform.rotation * Quaternion.Inverse(this.transform.rotation);)。
如果我们每一帧都这样计算,我们就会每次得到一个很小的旋转delta,它表示这一帧的旋转。我们也可以得到角度坐标轴的表示方式。(RotationDelta.ToAngleAxis(out angle, out axis))。
通过使用角度和轴,我们可以计算出三维的角速度。坐标轴是我们的单一向量,角度是角位移,时间是帧完成所需要的时间。(Time.fixedDeltaTime * angle * axis)

目前,我们仍然存在一些主要问题。


https://v.qq.com/txp/iframe/player.html?vid=r0303oaibpm&width=500&height=375&auto=0
视频说明:在一个开放的空间里,有一个红色的小狗形状的气球,还有一个玩家的控制器,控制器首先向前运动抓取了气球,控制器逆时针方向旋转,气球也跟着逆时针方向旋转,当旋转到一定的角度的时候,气球瞬间向顺时针方向转到底,玩家顺时针转到控制器,气球首先逆时针方向转到底,然后跟着控制器顺时针转动,转到中间位置后,控制器离开气球。
1)计算的角度有时候可能有过大。比如说,如果期望的旋转角度是偏离初始位置10度,我们可能发现有时候物体旋转了350度到达终点。
2)如果我们增大旋转的速度,我们会发现在到达最终旋转位置时的振动也会加强,特别是当物体和控制器的位置接近一致时。发现这个问题比较困难,但是一旦我们发现它,解决它并不复杂。
我们的第一个问题说明了一个事实,我们的旋转只能在一个方向进行。从技术上而言,角速度是一个伪矢量,它的方向只能由右手法则决定。这意味着我们计算的角速度的大小始终是正确的,但是方向却不是。这个问题的解决方案就是观察角度位移的大小。如果角度大于180度,我们就知道反方向旋转将会更加快。因此我们对每一个角度都减去360度,调整了矢量的符号从而可以控制旋转发生的方向。
第二问题并不是我们的数学有问题,而是Unity本身的问题。所有的刚体都有一个最大的角速度。为了让我们的旋转发生的足够快,我们使用了一个大的乘数,但是这也导致了角速度的大小超过了默认的最大角速度。对于这一问题的解决方案就是简单的在建立一个可交互对象时提高它的最大角速度。
代码:RotationDelta = AttachedHand.transform.rotation * Quaternion.Inverse(this.transform.rotation);PositionDelta = (PickupTransform.position - this.transform.position);
RotationDelta.ToAngleAxis(out angle, out axis);
if (angle > 180)    angle -= 360;
this.Rigidbody.angularVelocity = (Time.fixedDeltaTime * angle * axis) * AttachedRotationMagic;
this.Rigidbody.velocity = PositionDelta * AttachedPositionMagic * Time.fixedDeltaTime
大小相等,方向相反
在物体进行交互时考虑质量是一件更加重要的事情。如果玩家希望在游戏中推动一个大质量物体,那么他们要么使用一个相当重量或者更重的物体,要么快速的加速一个小质量的物体。采用一个气球推动一个箱子远不如使用另一个箱子来推动一个箱子。所有这些交互作用都不需要手动引入,由于我们使用的是物理交互系统,因此可以全部通过Unity和PhysX完成。
https://v.qq.com/txp/iframe/player.html?vid=e030388w2i1&width=500&height=375&auto=0
质量和交互-用一个气球撞击一个箱子
视频说明:在一个开放的空间里,有四个箱子,有两个散放在地面,还有两个堆在一起,地上有一个小狗形状的气球和斧头。玩家通过控制器捡起地上的小狗,向左快速运动试图撞击堆在一起的两个箱子,控制器穿透过去了,但是气球被挡住了,然后玩家将控制器移回原位,气球也跟着移回原位,然后玩家往复撞击了箱子几次,都没有效果,最后玩家将气球还原,并解除控制器的抓取动作。
https://v.qq.com/txp/iframe/player.html?vid=g0303hvxdcn&width=500&height=375&auto=0
质量和交互-用一个箱子撞击另一个箱子
视频说明:在一个开放的空间里,有四个箱子,有两个散放在地面,还有两个堆在一起,地上有一个斧头。玩家通过控制器捡起堆在上方的箱子,通过这个箱子推动下方的箱子的边角,让其在地板上滚动了两圈,然后利用类似吸引力的方式拖动了下方的箱子平移回原位,接着又吸引了小狗气球在箱子附近,最后将控制的箱子放回刚才推动的箱子的上方。
结语
当我们开始着手于建立一个完全基于物理法则的交互系统时,没人知道这将会是一个多么浩大的工程。同时,在虚拟现实世界中如何正确的利用速度来控制物体也并非易事。最后,基于物理学规则来建立虚拟现实的交互可以让游戏世界有足够的真实感和一致性,并且不需要通过设计一些小技巧去模拟现实,这也可以让我们在实施交互时有更大的自由度。

在虚拟现实中,交互扮演着一个非常重要的作用,也是一种非常扣人心弦的体验,我们相信它将成为许多虚拟现实必不可少的一部分。

近期,我们将会在GuiHub上公开我们的交互代码,让更多的人可以免费的使用它。我们坚信虚拟现实技术不仅仅会在游戏中改变人们的交互习惯,更会带了一个全新的技术变革。我们也期待着与大家共同进步和成功。


作者:Nick Abel \ Keith Bradner

翻译:陆于璇

腾讯游戏开发者平台长按,识别二维码,加关注
经验分享丨项目实践项目孵化丨渠道发行做有梦想的游戏人-GAME AND DREAM-

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存