徐玉如 黄玮
摘要:虚拟现实是當前IT行业的热点,虚拟家装系统是其应用之一。该研究首先介绍虚拟家装系统的总体架构。并在此基础上针对资源加载的效率、拖动管理的策略、射线管理模块等等各个功能的进行分析并最终在Unity3d环境下将其实现。
关键词:虚拟现实;资源加载;序列化
中图分类号:TP391 文献标识码:A 文章编号:1009-3044(2018)09-0098-02
1 背景
VR技术即虚拟现实技术[1]是当前IT界热门技术。当前VR技术已经在在工程[2]、机械[3]、展览[4]、旅游领域得到广泛应用。在家庭装修过程中使用VR技术进行虚拟家装,不仅可以让用户最终更好的预览家装的效果,而且,也便于用户参与家装的过程,不断试错,最终修改出适合自己体验的家装方案。
Unity3d[5]是进行VR/AR开发的主流引擎之一。在Unity3d引擎中提供了如粒子系统、射线系统、物理系统、碰撞检测、三维坐标体系等基本模块,开发者可在此基础上快速开发。本研究以Unity3d为底层技术介绍虚拟家装系统的架构设计与关键技术的实现。
2 系统架构的设计
虚拟家装系统需要实现以下的核心功能:
1)在虚拟场景中实现家具的选择、安装、移动、旋转。
2)对家具进行变更材质。
3)提供家具、材质的上传功能。
为实现上述功能,需要许多的辅助功能。例如,对家具模型的选择涉及模型的上传保存、加载以及界面上的选择操作等。此外还有许多的业务也均涉及存储、业务逻辑与UI等部分。因此在本系统中采用传统的三层进行设计,即数据访问、业务逻辑与界面三个部分。这三层的具体情况如图1所示。
与许多信息系统不同的是,该系统中的数据访问不与数据库打交道。该系统需要与外部交互的数据主要为3D模型与材质贴图,因此数据访问层的主要任务是文件的读写操作。其中文件访问类是最为底层的类。在此基础上为满足不同的应用分别提供序列化类、资源加载类、贴图读写类等模型。序列化类采用Json格式进行家装方案的保存与读取。资源加载类则采用异步读取的方式针对大文件进行访问以提供系统的性能。而贴图读取器则直接从进行贴图与二进制文件的交互。
业务逻辑层中的业务解释器类与状态管理器配合,将UI中获得的各种数据转换成业务逻辑中的各种状态,从而分离UI与业务逻辑。拖动管理器用于实现对物体的拖放、材质管理器则实现更换材质的功能、 位移管理器实现对物体位置的移动以及角度的旋转、射线管理器用于物体的选择。
在UI中对话框管理器主要实现弹出对话框的功能,用于与用户的交互。摄像机管理则实现对摄像机的上下左右移动,鼠标管理器则实现摄像机的水平旋转,在移动设备上进行VR内容呈现时则支持触屏操作。
3 系统架构的实现
3.1 资源加载功能的实现
在虚拟家装系统中,需要加载的资源是很多的,如各种房间、家具、电器的模型,各种材质图片等。更了更好提供用户体验,模型需要有一定的精度。但随着资源精度的提高,所需加载的文件的数据量大,这又会造成加载速度慢,造成卡顿效果,反而易给用户带来眩晕感。
Unity3d中要呈现一个物体需要有以下的操作:首先,将模型资源从磁盘加载到内存,并实例化该模型的原型对象,接着再根据该原型创建具体需要呈现的物体。这一过程需要涉及大量的IO操作,性能较差。本系统中采用原型模式+缓存机制+异步加载的方式实现。原型模式是指对象的创建方式不是采用动态生成的方式,而是根据目标对象的内存值直接复制出一个副本,原型模式通过增加内存的消耗提高了对象的创建效率。为了提高内存的使用率,通过引入哈希表对模型的原型进行缓存。而对于文件的加载,则可以采用异步预加载的方式。系统预加载的算法如下:
Step 1:(系统闲时)根据系统的路径获取资源目录下所有模型的文件列表。
Step 2:遍历文件列表,如果文件列表中的资源在缓存目录中,则不再加载该文件
否则,加载该文件,并将所加载的内容写入缓存。
为了显示场景中的物体,需要实例化模型对象。实例化模型对象的算法如下:
Step 1:如果缓存中有模型,则直接使用原型机制创建模型副本并呈现。
Step 2:如果缓存中不存在模型,则查看有没有启动加载该模型的异步线程,如果没有则启动。如果有,则提高该线程的加载优先级。
Step 3:加载完成后通过回调实例化模型,并将模型加入缓存。回到Step 1。
以上的方法可以较好的提高系统的性能。
3.2 拖动管理功能的实现
家装系统中需要进行各种家具位置的移动摆放。无论是通过鼠标、触摸屏、手柄或是其他的控制设备进行操作,本质上都是要先选中物体,然后通过控制设备的移动轨迹计算出虚拟现实三维坐标系统上物体的新坐标。由于控制设备在现实世界中的位移向量与三维坐标系中的移动向量不可能等同,例如控制设备(如鼠标)的移动是在二维平面上移动,其控制的物体却要在三维中移动。二维向量是无法直接映射到三维向量。为解决这一问题,先对三维中的物体进行降维,即一次仅限其在一个维度上运动,同时也仅考虑鼠标在一个维度上的分量,使得两个维度的向量建立起映射关系。这种方式可以通过辅助坐标系来实现。如图2所示的辅助坐标系,需要拖动物体时只能点中某个物体的三维坐标系箭头,使其沿一个方向进行拖动,从而建立起平面坐标系与三维坐标系的映射。
以上辅助坐标系采用第三方组件形式完成,但最为核心的拖动代码如下:
Step 1:得到要拖动的物体在屏幕的坐标screenSpace。
Step 2:记下鼠标的位置,并将鼠标位置转化为三维场景中的座坐标startPos。
Step 3:如果是鼠标拖动状态:
记下鼠标的位置,并将鼠标位置转化为三维场景中的坐标curScreenSpace。
计算两点curScreenSpace与startPos之间的向量,并将该向量转化为三维坐标系的向量V1。
计算V1在物体移动方向上的投影V2。V2即为物体需要移动的向量。
当前物体的座标与V2相加,得到目的地的坐标V3,将物体移到V3位置。
重置起始点。
等待下一帧,并重复Step 3。
3.3 射线管理功能的实现
射线管理功能是本系统中的一个基础功能,无论是更换材质、拖动物体或是UI元素交互,均需要使用射线功能。
射线功能实现的工作有两个,一是发出射线,二是获得射线路径上的物体。发出射线是通过场景中的摄像机来实现。通过Unity3D中的Camera向屏幕上指定一点发出射线。但在VR环境下,可能存在多摄像机的情况,例如使用Google Card Board类型的眼镜时,实际上左右眼分别对应一个摄像机。因此在这种情况下,使用状态模式来解决射线的切换问题。
图3是射线管理模块的设计类图,在RayState的抽象状态类中派生出NormalState与VRState两种状态,每个类均重写父类的CreateInstance方法用于生成射线对象。对于NormalState中的CreateInstance则用Unity3d的Ray类生成射线对象,而VRState中,则取两摄像机连线的垂直方向产生射线。在实际操作中,以两摄像机正前方向量之和为新射线的向量。
射线创建后可以通过与碰撞器的识别来判断所击中的物体,从而获得场景中对应的物体。伪码如下:
Ray ray = State.CreateInstance();
RaycastHit hit;
if(Physics.Raycast(ray,out hit)){
return hit.transform;
}
return null;
通过上述的伪码解决了选中物体的逻辑。另外射线管理模块使用状态模式的设计也解决了在不同设备呈现VR場景时不易管理的问题。
4 结束语
在介绍虚拟家装系统的功能后进行了系统整体结构的设计,并在此基础上介绍了最为核心的三个功能,即资源加载、拖动管理与射线管理。受制于篇幅,系统中还有如材质变更、序列化、对话框管理等许多也存在创新性的地方就不一一介绍。测试运行的结果证明了系统设计与实现有正确性。
参考文献:
[1] 李敏, 韩丰. 虚拟现实技术综述[J]. 软件导刊, 2010, 9(6): 142-144.
[2] 徐伟, 李龙华. 全断面硬岩掘进机事故处理虚拟仿真培训系统界面设计[J]. 科技广场, 2016(10): 40-43.
[3] 王娜. 基于Unity3D的采矿机械零件库系统设计[J]. 牡丹江师范学院学报:自然科学版, 2017(1): 32-33.
[4] 郭丹, 商书元. 基于Unity3D的虚拟博物馆展陈模型研究[J]. 北京服装学院学报:自然科学版, 2017, 37(2): 63-68.
[5] 黄玮, 余叶兰. 基于Unity3d的虚拟现实家装系统的设计与实现[J]. 新余学院学报, 2017, 22(3): 19-22.