在VR里建房子有什么神奇的地方。想象一下能够装配无重量汽车发动机,安排动态虚拟工作空间,或者用无限的砖头建造想象中的城堡。安排或组装虚拟对象是跨一系列体验的常见场景,特别是在教育方面,金宝博足球企业,以及工业培训——更不用说桌面和实时战略游戏了。

想象一下能够装配无重量汽车发动机,安排动态虚拟工作空间,或者用无限的砖头建造想象中的城堡。点击鸣叫对于我们最新的交互冲刺,我们探索了构建和堆叠交互如何感觉无缝,反应敏捷的,稳定。我们如何定位,堆栈,在保持完整物理模拟的细微差别和丰富性的同时,快速准确地组装虚拟对象?查看下面的结果或从188bet足球跳跃运动画廊.

挑战

徒手操作物理模拟的虚拟对象是一项极其复杂的任务。高级手动物理层188bet足球跳跃运动交互引擎使抓取和释放虚拟对象的基本元素感觉自然。这本身就是一项工程和交互设计的壮举。

尽管如此,精确的旋转,安置,和堆叠的物理支持对象-虽然非常可能-采取灵活的触摸。尤其是堆栈就是一个很好的例子。


堆放在VR不应该感觉像炸弹拆除。

当我们在物理世界中堆叠对象时,通过我们的触觉,我们对塔楼稳定性的许多方面都保持着跟踪。把一个块放在一个物体塔上,我们感觉到被保持的块何时何地与结构接触。在那一瞬间,我们感到实际的身体阻力。这种持续的信息流允许我们无缝地调整我们的运动和反馈回路中的力的应用——所以我们不会使塔不平衡。

在VR中解决这些问题的最简单方法是禁用物理并简单地移动对象网格。这成功地消除了持有的对象和其他对象之间的意外冲突,还有意外的轻触。


重力和惯性被禁用,我们可以随心所欲地组装积木。但是看起来还是很奇怪!!

然而,这个解决方案远非理想,精确旋转,安置,而对准仍然具有挑战性。此外,在虚拟对象上禁用物理使得与虚拟对象的交互远不那么引人注目。在VR/AR中,物理模拟虚拟交互具有先天的丰富性,只有当您能够赤手空拳时才会放大这种丰富性。

可部署脚手架

最好的VR/AR交互通常将真实世界的线索与媒体的独特可能性结合起来。研究我们如何使得在物理世界中组装东西更容易,我们观察了一些东西,比如尺子和测量带以便对齐,以及脚手架的概念。一种临时结构,用来支撑建筑材料.


可抓取网格是平面屏幕3D应用的共同特征。即使在VR中,我们也可以看到早期的例子,比如Google中非常好的实现阻碍.

VR中的可部署框架允许快速创建物理规则(暂时)不适用的交互空间。点击鸣叫然而,而不是用网格覆盖整个世界,我们提出了将它们用作离散体积工具的想法。这将是暂时的,可调整大小的三维网格,这将有助于创建虚拟对象的程序集-一个可部署的脚手架!当对象被放置在网格中时,它们会卡到位,被一个物理弹簧夹住,在整个交互过程中保持物理模拟。一旦用户完成了组装,他们可以停用网格。这释放了弹簧,并将对象返回到无约束的物理模拟。

为了创建这个脚手架系统,我们需要构建两个组件:(1)可部署的,可调整的,可抓拍的3D网格,以及(2)要组装的对象的示例集。随着我们进一步研究这个概念,网格本身将需要相当多的工程,尤其是冲刺时间表。

生成3D网格

构建以Scaffold交互为中心的可视网格非常简单——使用简单的预制件作为模板,实例化一个表示网格点的3D对象数组。为此,我们创建了一个ScaffoldGridVisual类。为了实现灵活性和组织性,我们将Scaffold的视觉网格特性与交互特性分开。在此,我们公开了基本参数,如点网格的比例和每个网格单元以世界单元表示的大小。

但是,虽然网格点阵列很容易创建,很明显,我们需要从一开始就进行优化。因为我们希望能够动态地改变脚手架的尺寸,我们每个脚手架可能有很多脚手架(每个场景可能有多个脚手架)。因此,在这种情况下,简单的静态批处理不是优化路径。

这使得创建一个定制的GPU实例着色器来呈现Scaffold网格中的点是值得的。这种类型的重复渲染相同的对象是伟大的放到GPU-它节省CPU周期和保持我们的帧率高。对于安装,我们只需要确保网格点网格的预制件具有使用GPU实例着色器的材料。

在开发的早期阶段,对点进行颜色编码是有帮助的。由于网格将动态调整大小,颜色有助于识别我们正在破坏和重新创建的东西或者我们的点顺序是否有序。(而且很漂亮,我们喜欢彩虹的东西。)

基于着色的网格悬停支持

在我们的工作中,我们努力使尽可能多的事情对我们的行为产生反应——提高存在感和魔力,使虚拟现实成为如此美妙的媒介。VR缺乏我们在物理世界中依赖的许多深度线索,因此,反应性对于增强我们的本体感觉也很重要。我们对身体不同部位的相对位置的感觉)。

记住这一点,我们并没有仅仅停留在做一个立方体的网格上。由于我们使用自定义着色器渲染网格点,我们可以向着色器中添加一些特性来帮助用户更好地理解他们手的位置和深度。

在着色器中,我们为悬停位置添加3D矢量。当我们渲染网格数组中每个立方体的每个顶点时,我们可以根据每个顶点离悬停位置的距离来缩放它的位置。然后,在我们的ScaffoldGridVisual类中,我们可以使用Leap Moti188bet足球on API来获得指尖位置,使用它来设置自定义的值“HoePo位置”在我们的网格点立方体的材质中可变。我们还可以在着色器中使用相同的悬停位置来基于相同的距离提升顶点的颜色。

结果是,当你的手靠近时,我们的网格点将增长和发光——使它更加响应和易于使用。

保存对象位置

随着网格的视觉部分正在进行中,现在是构建交互特性的时候了。为此,我们创建了一个ScaffoldGridInteraction类,该类位于预制层次结构中的SaffoldGridVisual类旁边。这个类有两个主要职责:维护一个记录,记录哪些对象被放置在哪个网格位置,当物体悬停时,找到离它最近的网格位置。

对于当前在脚手架中的对象及其网格位置的记录,在类中创建一个简单的Dictionary变量。它持有一个Vector3,用于存储对象占据的网格位置,以及ScaffoldBlockData数据类型。scaaffoldBlockData是一个自定义结构,它保存我们需要了解的每个对象:

  • 其变换
  • 它相对于网格父变换的本地位置
  • 局部旋转

这里最酷的部分是当脚手架空时,《词典》也是如此。它只需要为每个对象提供一个条目——这意味着当Scaffold中没有对象时,我们不必拥有大型的空数据数组。当对象被放置时,向字典添加条目,当对象被再次抓取时,删除条目。

制作脚手架反应块及其鬼魂

创建可以放置在新网格中(并与之对齐)的对象首先要向块模型中添加InteractionBeh.ur组件。结合交互引擎,这处理了使对象可抓取的重要任务。为了增强块与网格交互的能力,我们创建并添加了另一个Monobehaviour组件,我们称之为ScaffoldBeh.ur。这种行为尽可能多地处理块特定的逻辑,以便网格类保持不那么复杂并保持可用性(是的,这是个词。

就像网格本身一样,我们已经学会了思考交互以及交互本身的启迪。脚手架行为处理交互逻辑,例如当我们抓取时改变物理设置,地点,释放或放下我们的积木。但是,当块位于网格中时,这个类还创建并管理块的幽灵。脚手架行为:

  1. 当块被抓取并进入网格的盒式碰撞器时,生成透明鬼模型。
  2. 将幽灵放置在离抓握手最近的网格位置
  3. 将幽灵旋转到相对于网格的块最近的正交旋转
  4. 检查幽灵是否与网格中已经存在的任何块相交,如果是这样,改变鬼魂的颜色。

当网格中未抓住块时,它被放置和旋转类似于网格和鬼被摧毁。此外,我们还添加了另一个类,脚手架,以处理触发的各种外观更改——悬停,抓握,然后把积木放好。(稍后再详细介绍。)

使用交互引擎句柄调整网格大小

通过构建手柄来抓取和拖动,用户可以调整脚手架的大小以适合特定区域。我们创建了具有交互引擎行为的球形句柄,我们限制了它们控制轴的运动。ScaffoldGridVisual类具有对这些句柄的引用。当它们被拖动时,ScaffoldGridVisual动态重建网格。

当这种情况发生时,ScaffoldGridVisual检查来自ScaffoldGridInteraction类的Dictionary,以查看在创建或销毁网格点时网格点中是否有块。如果是这样,根据需要调用该块的ScaffoldBeh.ur类中的AddBlockToGrid()或RemoveBlockFromGrid()方法。

这个有价值的功能可以解锁各种有趣的和紧急的交互。这种方式,如果用户在脚手架中放置块并拖动句柄以使网格更小,块被释放,丢弃它们。相反地,如果手柄被拖动以使网格变大,在那些网格点处放置了块,然后街区又重新回到原来的位置!!

小部件阶段,国家,形状

现在我们有一个可调整大小的3D网格,在将鬼影对象位置捕捉到位之前能够显示鬼影对象的位置,现在是将这个功能捆绑到小部件中的时候了。我们希望能够使用多个脚手架,并且能够放弃脚手架小部件,让它在最近的表面活跃起来,自动对齐,并在着陆时自动扩展手柄。(呸!管理这个高级功能带来的所有状态更改,我们创建了一个Scaffold类以位于层次结构的顶部并控制其他类。

对于这个功能,我们有一个具有四个状态的简单状态机:

  • 锚定:脚手架的所有特征都是隐藏的,除了它的图标。
  • 举行:显示脚手架的网格和句柄。我们运用逻辑来寻找合适的表面。
  • 着陆:当脚手架被放开时,它动画和对齐到最近的表面。
  • 部署:这是主要的,脚手架网格及其句柄的活动状态。

顶级Scaffold类引用了三个类——ScaffoldGridInteraction,scaaffoldGridVisual,和脚手架。它的有限状态机根据需要控制状态改变时所有这些类的激活和禁用。脚手架组件的转换,连同它的所有子转换及其组件,然后拖动到一个预制文件夹,成为我们的Scaffold小部件。

完成小部件的层次结构显示了上图中的类如何在Unity场景中坐在一起。

部署前锚定阶段是网格的完全收缩状态,此时网格可以附加到浮动手动菜单槽或放置在环境中的某个位置,准备被接走在这种状态下,我们将小部件简化为3D图标,只有三个彩色的球体和一个较大的白色锚球。

一旦您选择了图标小部件,我们进入了等待/放置状态。图标成为具有完整特性的小部件,用它的红色,绿色和蓝色轴把手缩回。握着它,我们从窗口小部件中搜索合适的放置表面(通过层定义)。旋转小部件可以瞄准raycast。

当一个命中被注册时,我们显示扩展的小部件的一个幻影版本,对准目标表面。在指向一个可行的表面时放开小部件,使小部件动画到其目标位置,然后自动展开轴,生成3D脚手架。

部署的小部件需要几个特性:通过推动或抓取轴手柄来调整每个轴的大小的能力,一种把整个脚手架捡起来放到其他地方的方法,以及使支架失活/重新激活的能力。

小部件本身的形状经过了几次迭代,从测量磁带和其他手持建筑辅助工具以及基于软件的转换小工具中得到灵感。我们深入研究了轴手柄(红色,绿色,蓝色)锚杆(白色),以及白色住宅的隐含方向性。

有色轴手柄可以推动或抓取并拖动:

整个小部件和脚手架可以通过抓取较大的白色锚柄来拾取和重新定位。这暂时地将小部件返回到保持/放置状态,并且对新的可行的目标位置进行raycast。

只要轻轻一按开关,轴就可以收回,整个脚手架就停用了:

现在我们终于到了有趣的部分——把东西堆起来,然后把它们打倒!网格单元大小是可配置的,并且被扩展为手感良好且易于管理——比Lego块大,比砖头小。我们建模了一些简单的形状,并创建了一些倾斜的环境来设置和拆卸程序集。然后我们致力于在启示和可视化提示之间取得平衡,这将帮助用户快速准确地创建程序集,而不会感到不知所措。

当你的手靠近任何障碍物时,它的颜色稍微变浅,由接近驱动。当你拿起它,它会发出明亮的光芒,使“抓取”状态非常清楚:

当你把一个固定块放入网格时,一个白色的幽灵版本出现了,显示最近的可行位置和旋转。当鬼魂是白色的时候释放这个块将会把它卡到位。如果鬼魂与被占空间相交,鬼魂变红了。当幽灵是红色时释放块不会简单地将块卡入网格,让它从你手中掉下来。

一旦一个块进入网格,凹槽在角落里活跃起来,以强调它们被脚手架固定住的感觉。当关闭网格的杠杆被翻转并且脚手架轴收缩时,块缺口填充,块返回到正常静止状态。

最后一块,也许是最重要的,在整个互动过程中都在调谐肉体的感觉。供参考,以下是我们在块体被卡入脚手架后禁用物理时所看到的情况。

与区块的交互(或缺少交互)突然感到空洞和不令人满意。突然将交互性规则从冲突切换到非冲突感觉不一致。也许,如果块放在网格中时变成了鬼影,这种变化不会太刺耳……但是如果我们添加弹簧并保持块体的可碰撞性,会发生什么呢??

好多了!现在,它感觉更像是网格是一个结构化的力场,保持块在适当的位置。然而,由于这些块还彼此碰撞,当组件受到强烈干扰时,当弹簧试图将它们推回位置时,这些块可以相互抵触。

幸运的是,因为我们在VR中,我们可以简单地使用层来设置网格中的块,以便只与手碰撞,而不是彼此碰撞。

这感觉像是在整个交互过程中保持物理性的正确平衡,而不会因为碰撞混乱而牺牲速度或准确性。现在是玩积木的时候了!!





图片来源:跳跃运动,188bet足球卡斯托克培养基,谷歌Sunghoon Jung史诗游戏

这篇文章的删节版最初发表在道托VR.一中文版也有。