漫步VR——Unity语音聊天室开发

时间:2022-04-27
本文章向大家介绍漫步VR——Unity语音聊天室开发,主要内容包括一、背景介绍、二、客户端开发、三、聊天室动画功能实现、四、视线交互、五、研发小tips、调试、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

一、背景介绍

VR是什么

虚拟现实VirtualReality的英语缩写。VR 主要有手机盒子、头盔和一体机三种。

虚拟现实技术是一种可以创建和体验虚拟世界的计算机仿真系统它利用计算机生成一种模拟环境是一种多源信息融合的交互式的三维动态视景和实体行为的系统仿真使用户沉浸到该环境中。

智平测试组耗时一个月的时间,研发了一款基于Oculus的VR语音聊天室软件,现做个阶段性总结:

研发语言

客户端: unity+ C#

语音sdk: Apollo

后台: python+ Flask

硬件环境

VR环境: oculusdk 2

运行平台:windows

二、客户端开发

1、环境配置

引擎unity安装:https://unity3d.com/cn/get-unity/download/archive

Unity5.1版本后全力支持VR开发,所以最好下载5.1版本以后的版本。安装过程是一键式安装。

编译Support包:unity可以很方便移植到多个平台上,依赖的即是下载安装对应unity版本的Support-for-Editor。下载安装方式是,打开安装的unity,随便新建一个工程,打开File->BuildSettings如下图,如果没有下载平台的Support-for-Editor,就会有下图中的OpenDownload page,点击按钮就会下载,然后就是一键式安装,重启unity可生效。

UnityVR支持:

1、下载OVRPluginfor Unity5(https://developer.oculus.com/downloads/game-engines/1.3.2/OVRPlugin_for_Unity_5),将压缩包中对应的unity版本的文件夹(如5.4,5.3)中的文件解压到Unity安装目录的/Editor/Data/VR/Unity/下边;

2、打开Unity,Edit->ProjectSettings->players设置Virtual Reality Supported如下图;

3、OculusVR的runtime版本大于0.8;

4、设置VR的显示模式为Direct(最新的runtime在Oculus的安装目录的/Support/oculus-runtime/DirctDisplayConfig.exe设置)。完成这些步骤以后可以在Unity中直将工程运行在VR上。

Oculusruntime安装:

0.8以下的版本可在https://developer.oculus.com/downloads直接下载,新版需要在https://developer.oculus.com先下载下载器,然后根据提示下载800多兆安装包,等待下载完(如果网络被墙,下载失败,可以使用使用V**访问外国网站下载),将VR的HDMI和显卡连接(电脑至少有独立显卡),Tracker连USB3.0(USB2.0也可以,会影响VR的延时),然后就是一键式安装。

注意:1、在安装新版本的runtime之前要先卸载旧版本;

2、电脑显卡驱动版本更新为最新版),卸载MicrosoftVisual C++ 2015相关的组件。

完成上面四个步骤的准备后便可以在Unity中尽情绘制你的VR世界了。

Oculus sdk配置流程:

1、下载OVRPluginfor Unity5(https://developer.oculus.com/downloads/game-engines/1.3.2/OVRPlugin_for_Unity_5),将压缩包中对应的unity版本的文件夹(如5.4,5.3)中的文件解压到Unity安装目录的/Editor/Data/VR/Unity/下边。

2、下载OculusUtilities for Unity5(https://developer.oculus.com/downloads/game-engines/1.5.0/Oculus_Utilities_for_Unity_5),在Unity3d中importCustom Package,导入下载压缩包中OculusUtilties目录下的OculusUtilities.unitypackage官方插件包,在我们的工程下会生成OVR总目录,看下其中包含的子目录:

  • Editor:包含了新增Unity编辑器功能的脚本。
  • Materials:包含了内置图形组件所需的材质。
  • Meshes:包含OVR脚本所需的网格,例如TrackerBounds。
  • Moonlight:包含了开发GearVR所需的一些基本的类、材质、组件等。
  • Prefabs:包含了三个支持VR场景开发的预置体OVRCameraRig相机预置体、OVRTrackerBounds位置跟踪预置体、OVRPlayerController角色控制预置体。
  • Scenes:demo场景。
  • Scripts:包含用来绑定VR框架和Unity组件的C#脚本。
  • Textures:部分组件用到的纹理贴图。

3、将OVRPlayerController组件添加到场景中,调整位置,大小,碰撞器等。

4、调整OVRPlayerController里的CharacterController以适应角色控制的需求。

5、根据需求修改OVRPlayerController源码,适配产品提出的需求。

6、焦点控制逻辑在OVR/Gaze/目录下,目前焦点控制方式支持Click和Gaze两种方式,Gaze的响应时间支持自定义,需要添加到2D控件的EventSystem中,并需要与默认的StandaloneInputModule的enable保持互斥状态。

官方文档https://developer.oculus.com/documentation

2、聊天室主要功能模块业务逻辑架构图

2.1 多人实时语音聊天

2.2 客户端/后台用户管理:

2.3 语音发送彩蛋

三、聊天室动画功能实现

聊天室动画涉及的内容主要有

1、人物在房间内的走动

2、彩蛋效果的添加

3、多个角色(三个)动画的适配

第一部分:人物在房间内的走动

人物走动部分的实现稍微复杂一些,用到了2DBlendtree,BlendTree是把多个动画进行合并到一个状态中,举个例子:把左前,往前走,右前的动画放到一个BlendTree中,用一个float型参数控制;好处:减少状态个数

2D是什么概念呢,还是举个例子:如果我想要用键盘的左右方向键控制动画的左前右转,用上下键控制idle走和跑,那么我可以用两个float变量分别控制两个方向的动画,这就是2DBlendTree。

来,让我们为聊天室的走动添加2D BlendTree吧!

第一步:添加动画资源,添加如下动画资源(直接导入fbx文件)

第二步:调整动画资源中的animationchip,完成以下的动画片段

这里有个坑提前说一下:

1、LoopTime选项一定选上,否则动画只转向不运动

2、这个选项勾上,否则动画会跑到地面底下

第三步:在状态机中添加BlendTree(右键添加),双击进入BlendTree界面进行设置

1、设置direction和speed两个参数;

2、选择为2DBlendTree;

3、添加动画;

4、调整动画在坐标系中的位置,便于代码控制

注,可以通过调整BlendTree中的speed和direction控制块预览动画效果。

第四步,代码控制,主要是控制横向的方向和纵向的速度。

代码很简单,就不用多讲了

第二部分:彩蛋效果的添加

彩蛋效果是,按键盘的某些按键可以触发一些动画效果;再聊天室中,也可以通过语音触发一些动画效果,这里做的就是动画效果。

还记得前面提到的动画控制器中的layer层嘛,就是通过不同层添加的动画效果

有两种方式添加,第一种方式是,直接从其他状态切换到菜单动画;优点是:非常简单;缺点是:动画不会叠加,要终止之前的动画后,才能播放菜单动画。

第二种是添加一个新的layer,为新的层添加Avatar蒙板,此种添加的好处是,添加的蒙板动画可以和底层动画叠加,可以在底层动画运动的同时做出菜单动作,例如:在走动的过程中挥手。缺点是:要自己做蒙板(其实也很简单啦)

因为聊天室内基本上走动比较少,之前预定是静止时添加彩蛋,需求决定实现,所以采用的是第一种方式,因为比较简单,这里就不赘述了。

我们重点说下第二种方式:

第一步:为状态机添加一个新层,命名为Wave

第二步:创建一个蒙板,并且配置新添加的层

1、在assets的某个文件中创建蒙板:右键》create》avatarmask,我们这里命名为WaveMask;

2、单击此文件,在右侧Inspector中查看,配置蒙板如下图(除右手臂外,其他都禁用)

3、配置Wave层如下

第三步:添加彩蛋动画

1、添加挥手动画资源

,把动画拖动到wave层,设置如下(添加一个空的状态不加任何动画)

2、添加一个WaveBool的bool型变量控制挥手(初始值设为false)

3、添加EmptyState到IdleWave的transition的条件控制(为true时触发此状态)

4、添加控制代码

在初始化代码中设置动画层的权重为1

通过按下H键,控制播放挥手

注意:

EmptyState—>IdleWave的transition中下面参数最好设置为false

IdleWave—>EmptyState的transition中下面参数一定设置为true

要在Start()函数中初始化时,设置层级的权重为1(这里主要是为了防止一些异常情况下,层级中初始设置的权重被重置为0,另加一层保护机制)

最后,点击运行,在按方向键控制运动的同时,按下H键,你会发现,你的动画同时挥手了。

第三部分:多个角色(三个)动画的适配

其实Unity动画系统Mecanim的retargeting,我觉的有两层意思

第一,就是导入的模型骨骼,和系统内部的内置的骨骼肌肉进行映射关联

第二,是把已知的动画控制器control和导入的新模型进行匹配,大家还记得这个图嘛

导入了带有蒙皮的动画模型,生成avatar,关联动画控制器,新导入的模型就按照控制器的方式动起来了。

四、视线交互

Unity的Camera支持Raycasting特性,其实际功能是从视野中心向世界场景中投射一条线,射线Ray是object,能够指向视野中的具体的点,可以返回相应的坐标或者触碰到的物体信息,这个信息可以通过RaycastHit 对象获取到。

代码实例

using UnityEngine;
using System.Collections;
public class eyeControl : MonoBehaviour {
 Ray ray;
 RaycastHit hitInfo;
 public Transform mainCamera;
 void Update () {
 //声明ray,方向是主Camera的前方
        ray = new Ray(mainCamera.transform.position, mainCamera.transform.forward);
 //Physics检测碰撞体,得到被视线碰撞到的物体objectHit
if (Physics.Raycast (ray, out hitInfo)) {
 Transform objectHit = hitInfo.transform;
//针对碰撞体做处理,实现视线交互动作
}
}
}

需要注意的是如果想要Raycast能够碰撞对应物体进行控制,需要给object添加Collider,Collider的形状可以和物体模型完全一致。

也可以设置为特定几何形状的碰撞体,如胶囊形状、球形。

OVRPlugin Camera绑定问题

使用Oculus VR进行开发调试时,需要使用Oculus开发插件里的OVRPlayerController来进行Camera绑定,否则对应的视线无法从正确的VR摄像头发出。

选中OVRPlayerController中的CenterEyeAnchor,使视线和中央视野锚点绑定

视线周围实现了一个进度圈,在视线碰撞到物体时,视线周围会出现对应的进度条提示用户当前存在操作。

实现效果图如下:

五、研发小tips

UI

在传统的非VR项目中,UI通常显示在界面的顶部,用来显示生命值,得分之类的信息,通常被称为HUD。在Unity中,添加HUD样式的非剧情型UI相对简单,只需要在UI Canvas的Render Mode中选择Screen Space——Overlay或者是Screen Space-Camera。

但是这种UI界面对VR基本不适用,我们的眼睛无法聚焦在如此近的物体上,而Unity VR中根本就不支持Screen Space-Overlay。

和前面的UI不同的是,我们需要将UI放置到环境中,并在Canvas的Render Mode中选择World Space模式。通过这种方式,就可以让用户的眼睛聚焦到UI上了。

因为UI被放置在环境中,有可能我们通过摄像机看到UI会是侧面,或者是反过来的。

如果要使得UI一直在摄像机中正常显示,可以将UI的rotation绑定到mainCamera的rotation上。如下图,使用Oculus时,我们可以将UI绑定到CenterEyeAnchor上。

GameObject

1、如果是在场景中固有的GameObject,即将GameObject直接拖到Hierarchy中的,在其他GameObject的脚本中需要使用的该GameObject的一些属性是,尽量避免使用GameObject.Find(),而是在脚本中申明public GameObject;然后在Script直接赋值。

2、GameObject的SendMessage()方法,可以方便调用到绑定在GameObject上的脚本里的方法,但是调不到GameObject的子物体上的脚本。

3、GameObject.Instantiate(Resources.Load("Dude_CharacterNet"))

as GameObject创建物体只能在主线程中创建,不能在子线程中进行。Mono脚本的主线程有Start(),UpDate(),Awake()等。

调试

1、Unity在IDE里面运行工程时,在Console界面可以看到开发哥打的Log以及系统抛的异常警告等。

2、在编译的时候勾选play->use player log,运行编译生成的exe时,在同级目录_EXECNAME_Data_ouyput_log.txt的文件中保存有Debug.Log的信息。

3、在执行EXE时实时输出Debug.Log的方法:http://blog.csdn.net/cartzhang/article/details/49818953

32位dll

当unity IDE是64位,使用了32位dll时,在IDE里面运行项目时,会提示dll找不到的状况(System.DllNotFoundException)。这时应将工程编译成exe后再运行,且编译的时候Architeture应选择X86。