叶 诚,罗 训
(天津理工大学 计算机科学与工程学院,天津 300384)
现阶段场景模型生成技术并不发达,程序员在处理生成模型场景问题上还存在很多情况没有解决.本研究在游戏引擎的实验环境下,讨论了大规模复杂场景生成阶段的一些重要问题,优化了相关算法.本文主要研究大规模复杂场景生成后场景模型的优化,根据模型和摄像机的远近实时调用不同层级的模型方面进行研究.大型复杂生成场景文件在游戏引擎中的漫游存在着模型渲染上和模型调取的问题,该研究使用了模型加载及其渲染优化技术,优化了场景漫游的工程简化了制作流程;在模型场景渲染技术上,通过使用一种基于LOD 场景模型的新型算法,解决了大规模复杂场景的实时渲染有许多技术上的难点,主要包括海量地形数据的表示和组织、动态场景的管理以及场景的真实感表现等.即按照生成模型的规模大小,使用模型切割代码将模型切割成尺寸大小均等的不同尺寸,满足工程对于场景漫游的要求;相关论文研究了关于大规模地形的快速渲染方法,其思想是将之前分割好的地块都先简化为一些不同细节层次的网格模型,存储在外部存储介质上.程序根据摄像机距离模型的远近调取合适的地形块导入内存,再进行模型的渲染.这种方法的缺陷是增加了很多的步骤,在不同的模型切换时会产生视觉上的卡顿问题.本文对于自动LOD 技术进行探讨采用网格简化算法结合视点的动态LOD 技术,提高了帧率减少了当前占用CPU 进行计算的时间,并且减少了摄像机下的三角形和顶点数从而减少了渲染的工作量.
本文在游戏引擎中使用天津工业大学的生成模型(如图1)进行漫游,采用不同方法对该工程进行优化处理,提出将LOD 技术和动态网格简化算法并行计算形成一种新型的自动LOD 构建算法,主要贡献可以概括为:
(1)将游戏引擎中LOD 技术与动态网格简化算法并行节省渲染时间.
(2)提出了自动LOD 构建方法只需要使用一套模型就可以应用LOD 技术.
图1 天津工业大学模型
在大型场景中经常使用的优化算法主要有:LOD技术,遮挡剔除算法,动态加载,本文主要对这LOD 技术和网格简化算法进行了结合改进从而提出了自动LOD 算法.
LOD 技术,也称为层次细节技术,是在实时渲染显示系统中采取的细节省略技术,此技术于1976年由Clark 提出[1].作为目前主要的场景优化方法,它根据物体的重要性、视点的相对速度或者位置等衡量标准,动态改变场景中三维模型的复杂程度,模型距离视点越近,显示的模型细节越丰富,从而降低了CPU 和GPU需要处理的的顶点数量,提高场景的渲染速度[2].在复杂模型的动态显示中,当观察点距离某一物体很近时,该物体的图像将在屏幕上占据较多的像素点;而当观察点距离某一物体很远时,该物体的图像只能在屏幕上占据很少的像素点.在这种情况下,用大量的面去精确表示该物体是不必要的[3].认为当物体覆盖屏幕较小区域时,可以使用该物体描述较粗的模型,并给出了一个用于可见面判定算法的几何层次模型,以便对复杂场景进行快速绘制.LOD 技术在不影响画面视觉效果的条件下,通过逐次简化景物的表面细节来减少场景的几何复杂性,从而提高绘制算法的效率.该技术通常对每一原始多面体模型建立几个不同精度的几何模型.与原模型相比,每个模型均保留了一定层次的细节.在绘制时,根据不同的标准选择适当的层次模型来表示物体.LOD 技术具有广泛的应用领域.目前在实时图像通信、交互式可视化、虚拟现实、地形表示、飞行模拟、碰撞检测、限时图形绘制等领域都得到了应用,已经成为一项要害技术.很多造型软件和VR 开发系统都开始支持LOD 模型表示.LOD 生成的一种常用方法是网格简化.目前常用的网格简化方式有边压缩、面收缩、点聚合和顶点删除等[4].
遮挡剔除算法利用遮挡剔除(occlusion culling)技术,在游戏引擎中使用遮挡剔除时,会在渲染对象被送进渲染管线之前,将因为遮挡而不会被看到的隐藏对象或隐藏面进行剔除,从而减少了每帧的渲染数据量,提高了渲染性能[5].可见性剔除是提高大规模复杂场景的加速技术之一,目的是减少送入图形管线的面片数量,降低场景规模增长对图形系统的负担[6].对于给定的场景和观察视点,通过判断场景中物体的可见性,快速拒绝那些显然不可见的绘制元素,从而减少送入图形绘制管线的几何复杂度[7].在遮挡密集的场景中,性能提升会更加明显.遮挡剔除是当一个物体被其他物体遮挡住而不在摄像机的可视范围内时,不对其进行渲染.在3D 图形计算中并不是一个自动进行的过程,因为在绝大多数情况下离相机最远的物体首先被渲染,靠近摄像机的物体后渲染,并覆盖先前渲染的物体(这种重复渲染又叫做“OverDraw”),它不同于视锥剪裁.视锥剪裁只是不渲染摄像机视角范围外的物体,而对于那些被其他物体遮挡,但是依然在镜头范围内的物体,则不会被视锥剔除.当然当你使用遮挡剔除时,视锥裁剪还是会生效的.由于地形场景一般较为复杂,对CPU 开销很大.为了降低地形的遮挡剔除过程中CPU的负荷,提出了以GPU 具有遮挡查询功能为基础的遮挡剔除算法[8].
在游戏引擎中,如果想使用传统的LOD 技术(如图2)就必须先将面数最大的模型分别简化为几种面数不同,导出后再放入游戏引擎中使用LOD 技术优化工程.在这种新型的LOD 技术中,动态网格简化算法采用网格预先简化的方法事先生成LOD 模型避免了直接使用网格简化算法所需完成的大量计算,有效地降低了算法的时间开销.在串行计算环境下,网格简化算法使得一些较小规模(包含1 05以下量级三角面单元)的网格模型的在交互帧率下的动态LOD 模型构建成为可能.然而在面对大规模网格模型(包含1 05及以上量级三角面单元)时,却仍无法满足交互帧率绘制需求.
在动态网格简化算法使用在大规模复杂模型的时候其时间性能需要有所提升,该理论基于网格的动态LOD 构建方法,并且使用了三维模型的简化算法,创造出一个新型高效率的自动LOD 算法,如图3.
图2 传统LOD 加载算法处理步骤
图3 自动LOD 加载算法处理步骤
算法主要具备如下优势:
(1)适用于较大面数的模型,具备良好的扩展性.
(2)只需要一套模型.
(3)可以自由缩减模型的面数.
自动LOD 加载模型总体流程如图4所示.
图4 自动LOD 加载模型流程
为了能够对模型使用网格简化选择三角边坍缩的办法实现,可以让两个顶点并成一个顶点,如图5所示.
图5 三角边坍缩
要实现边uv的坍缩需要删除两侧的面A和B,使用点v来代替点u,需要进行点的连接操作,目标是连接点v和点u的邻点还要除去点u,点v为点u的坍缩目标.
对于1 个实体模型(具有封闭的边界,根据边界可以将空间分为模型内部和模型外部2 部分),1 次坍缩,可以移除2 个三角面,3 条边和1 个顶点.通过反复的迭代,最终就会使模型简化到预期的面数.
如果想要删除掉某个点还要尽量保持原始模型外观这就需要考虑到坍缩的代价公式如下:
在式(1)中顶点u的三角形被包含于集合Tu里,顶点u和顶点v的三角形被包含于集合Tuv里.
式(1)中需要考虑两个顶点点u坍缩到点v并且需要将顶点u删除这一系列操作所花费的代价.首先需要处理的是边,在网格简化的流程中,无关紧要的部分是首要剔除的部分.其次应该要注意顶点u附近的曲率,因为只有当点周围的曲率越平坦,那么这个点也就越不重要.值得关注的是,连个顶点从点u坍缩到点v和从点v坍缩到点u的代价有所不同.
根据上述公式,依赖于针对点与其周围邻点坍缩的代价进行计算,再决定以代价最小的邻点为目标进行坍缩运算.
根据以上的描述,可以将实现分为以下步骤:
(1)遍历模型上点、边和面的关系.
(2)计算坍缩代价和坍缩目标,并排序.
(3)通过公式找到坍缩代价最小的顶点,通过衡量相邻顶点的的坍缩代价和坍缩目标,实时调整有序列表.
(4)再次遍历顶点,计算设置顶点数量是否小于现顶点数量,如果是则重复第(3)步.
因为在程序运行的时候不能够实时进行上述步骤,特别是第(2)步,因为全部的顶点被遍历了很多次,不必要的工作量过于繁重.因此,可以考虑将工作分成离线烘培和运行时这两个步骤,具体实现步骤如图6所示.
图6 实现步骤
离线烘焙会输出两个int 数组:permutation和vertex_map.
步骤:
(1)收集顶点信息:主要是顶点位置和index,另外需要初始化两个列表:包含顶点的三角面列表和顶点的邻居列表.
(2)收集三角面信息:需要得到模型上所有三角面里所含有的顶点和计算法线(目的是计算曲率).并且不断更新顶点的三角面列表将新的三角形填入列表,还需要使每个顶点加入另外两个顶点的邻居列表中.
(3)通过不断分析点与该点邻点的坍缩代价,决定坍缩代价最小的邻点为最终的目标.
(4)依据坍缩代价对所有的顶点进行排序.
(5)替换坍缩代价最小的顶点:根据坍缩公式设法得到代价最小的点u和它的邻边目标点v,读取包含顶点u的三角面列表,只要哪个三角面里面含有顶点v就删除该三角面,如果不能遍历到就将顶点u与顶点v进行交换.再次分析顶点u邻点的坍缩代价以及坍缩目标,根据最新的信息重新编排列表.
(6)令permutation[u.index]=当前顶点数量,令vertex_map[u.index]=v.index(如果没有坍缩目标,则赋值为-1).
(7)目前的点数大于0,如果是将返回第(5)步.
permutation保存了每个顶点被移除的倒数次序(1 是最后被移除的,最大的是第一个被移除的),vertex_map保存了每个顶点的坍缩目标的位置.
输入需要绘制的最大顶点数量n.
步骤:
(1)遍历三角面.
①获得当前三角面的三个顶点的index,即idx0、idx1和idx2.
②如果permutation[idx0]=n则idx0=vertex_map[idx0],否则执行第⑤步.
③如果idx0==-1 oridx1==idx0 oridx2==idx0,该三角面不参与绘制.同理映射并判断idx1 和idx2.
④返回第①步.
⑤当前三角面加入绘制列表.
(2)根据三角面的数据,整理顶点属性.
值得注意的是,员网格信息将不会被删除,再程序运行的时候,还能够再任意的层次细节模型上切换.
如果想要有出色的游戏性能以及更佳的画面效果,该研究还可继续改进上述步骤:
(1)最小堆排序:在离线烘培的第(4)步中,应该考虑需删除点的邻点的坍缩代价,同时坍缩列表也要随之更新.因此可以选择最小优先队列(最小堆)记住顶点和坍缩代价,根据新的信息重新完善顶点的顺序.
(2)删除不用顶点:需要提高帧率并通过减少摄像机前的三角面和顶点降低渲染压力,在第(2)步中,需要依靠三角面的数据对Mesh 的顶点数组(还有uv、uv2、colors、normals、tangents、boneWeights等)和三角面数组进行重新排列.
(3)边界点处理:在处理过程中有两个问题比较棘手,一种是不闭合的三角面,例如飘带、披风等.另外一种是两个垫高点虽然有相同的坐标,但是不同的uv或normal,例如Unity3D 的Sphere 是有一条接缝的.假如这两种情况不进行参考,在坍缩的过程中,将会出现没能指出对的坍缩目标来代替原顶点,会发生镂空和破损的情况.根据上面说的问题,我们在考虑坍缩消耗的问题上,会将这些边缘点的曲率设为2 (可以在编辑器里调整).
(4)内存优化:如果不想多次重新建立Mesh 的vertices等数组,可以选择unsafe 的方式来改变数组的大小.
(5)JobSystem:离线烘焙中使用了JobSystem 来加速烘焙.
本论文选取天津工业大学的生成模型场景为例子,验证过程为自动LOD 算法与遮挡删除技术,动态加载,普通漫游分别对同一场景随即视点位置进行渲染,对比各项渲染数据.
FPS (Time per frame and FPS):Frames Per Seconds表示引擎处理和渲染一个游戏帧所花费的时间,该数字主要受到场景中渲染物体数量和GPU 性能的影响,FPS 数值越高,游戏场景的漫游体验会更加平稳和舒适.
CPU:获取到当前占用CPU 进行计算的时间绝对值或时间点,如果Unity 主进程处于挂断或休眠状态时,CPU time 将会保持不变.
Tris &Verts:摄像机下的所有三角形和顶点这也是主要瓶颈.
图7中描述了各个算法之间在同一场景下,摄像机前三角面和顶点的数量,三角面与顶点的数量呈反比,数量越大计算机所需要做的工作就越多.
图7 实验数据对比
图8中描述了各个算法之间在同一场景下,帧率和CPU 进行计算的时间,因为FPS 和CPU 的数值与三角面和顶点数量有直接关系,所以提出自动LOD 算法.
图8 实验数据对比
文中使用的方法自动LOD 考虑到了之前几种优化方法的缺点(算法优缺点对比如表1所示),通过使用三角边坍缩算法,不仅节省了模型导出和导入步骤还节省了大量的内存空间.
表1 算法优缺点对比
针对大型场景漫游提出了新的自动LOD 技术,实验解决了只使用一套生成模型就可以应用LOD 技术的方法,减少了工作的步骤,对工程中大型生成场景模型的漫游实施了优化处理,不仅提高游戏帧率,而且减少当前占用CPU 进行计算的时间,还节省了不必要的存储空间,具有一定的参考价值和实际意义.