现在虚拟城市仿真,以及军事仿真项目越来越多,开发此类项目,首先面对的一个比较棘手的问题是内存管理,城市中的建筑物特别多,这些建筑物的面数和贴图都要被加到内存中的,内存有自己的峰值,超过了就要崩掉,所以内存的优化是必须要面对以及解决的问题。
Unity官方提供了Occlusion Culling的裁剪操作,网上有很多文章对它做了相关介绍,因为它是Unity自身提供的,对于我们程序员来说就是一个黑盒子,并不利于我们自己去进一步的优化,最好的方式就是自己通过代码重新实现一个Occlusion Culling算法,当然对于城市仿真只做Occlusion Culling是不能完全解决问题的,我们需要从几个方面入手搞定它,本篇博文就给读者介绍这些针对密集建筑物的优化。下面先看看虚拟仿真的场景:
面对这么复杂的场景,我们该如何去解决呢?本篇博客教给开发者解决问题的方法,我们会从五个方面来实现我们的密集建筑物解决方案。
AutoLOD
摄像机是用来裁剪的,我们可以设置摄像机的远裁剪面距离做一些优化操作,当然如果是在飞行模拟,这种方法是不可取的,因为我们要求视野是足够大的,这样摄像机视锥体内的物体肯定会很多的,效率就会下降,解决这个问题很自然的想到LOD算法,虚拟场景中的建筑是非常多的,我们不可能让美术帮我们把每个建筑都进行减面处理,工作量是相当大的,LOD是根据摄像机的距离远近相应的显示不同面数的建筑物,我们需要想一种能够自动帮我做LOD处理的算法,AutoLOD就是为解决这个问题而生的。LOD模型显示如下所示:
AutoLOD是Unity官方为我们提供了一个比较好的插件,可以帮我们自动实现LOD算法,进而对场景中的建筑物进行优化,代码下载地址:
https://github.com/Unity-Technologies/AutoLOD
将其代码导入到项目工程中后,然后需要我们做一些设置操作:
AutoLOD实现的效率比较高,占的显存少,测试的结果如下所示:
其实我们还可以找到一种更好的算法,结合AutoLOD算法一起优化建筑物的面数以及材质,也是第二个步骤要讲解的内容——Amplify Impostors插件,下面介绍Amplify Impostors插件。
Amplify Impostors
这个是Asset store提供的解决方案,它的基本原理是根据摄像机的距离,将原物体生成一个仿真物体,仿真物体面数非常少的,外形跟原物体几乎是一样的,而且还可以旋转,缩放,位移,并且可以投影,效果如下所示:
仿真对象的生成,我们可以使用GPU实例化,该技术非常适合用于移动端,它对于面数的优化非常好,运行效率测试如下所示:
在实际项目运行中,看一下树木模型实现的效果图如下所示:
除了对模型的优化,我们还可以对纹理图片进行优化,对应的是Amplify Texture。
代码下载地址:
链接:https://pan.baidu.com/s/1VKRwmn7QCzjIM0mqnq0RCA 密码:yrko
Amplify Texture
Amplify Texture是一种纹理虚拟化,该技术可以绕过常见的纹理大小,数量和视频内存限制,而不会影响质量,性能或大小。 使用Unity 2017,每个纹理最高可达16384 x 16384像素。该技术处理几百张贴图都没有任何问题。
虚拟纹理的工作原理是将所有纹理切割成可管理的图块(或页面),并将它们存储在针对流媒体自定义数据文件中; 在运行时, Amplify Texture始终使用可用的最大分辨率虚拟化纹理,无论是8k或16k纹理(Unity 2017每纹理32k),原始大小永远不会受到影响,虚拟贴图其实就是一张大的图集,中间会生成一张数据索引文件,它存放了图片的索引,大小,针对模型的ID信息等等。根据模型的加载通过索引文件在虚拟贴图上查找对应模型的贴图,将对应的虚拟贴图加载到内存中,将纹理映射到模型上面。
技术实现参考网址:http://amplify.pt/unity/amplify-texture-2/
关于模型的优化技术差不多就讲完了,运用上面的技术完全可以帮助我们处理密集型建筑模型。下面还有一项重要的技术讲解,也就是我们说的场景裁剪,我们使用的算法也是Occlusion Culling。
Occlusion Culling
Occlusion Culling也是一种遮挡裁剪,可以将遮挡住的物体直接从内存中移除,或者从摄像机可视空间移除,这里讲的算法与Unity自带的Occlusion Culling是不一样的,该算法尤其对建筑物密集的场景非常实用,先看看Occlusion Culling是如何工作的?如下图所示:
在此介绍两种利用Occlusion Culling方法解决遮挡剔除的问题,首先介绍的方法是
Potentially visible set
参考网址:https://en.wikipedia.org/wiki/Potentially_visible_set
具体实现步骤如下所示:
1、地图切割成Tile,Tile切割成Portal(视口)和Cell(大物件、中物件、小物件);
2、检测场景物件所属Cell,一个物件可以属于多个Cell;
3、 利用蒙特卡洛方法Portal随机一些起点,Cell随机一些终点(根据大、中、小随机不同数量的点);
4、 双层遍历每个Portal和Cell,射线检测是否阻挡,如果阻挡,判断阻挡物是否被在当前检测Cell内,如果是,Cell可见;(注,当前设置两个高度检测)
5、 保存检测数据,运行时加载解析,根据玩家位置检测当前Portal,然后遍历场景所有Cell内Item,判断显示和隐藏;
总之:
此pvs方案相比于Unity OcclusionCulling,更适合大地图比如5000米x5000米,pvs生成data基于Tile,支持动态加载,占用内存忽略不计,同时CPU消耗也极少;
先看看没有使用Occlusion Culling裁剪算法之前,实现效果图如下所示:
应用了Occlusion Culling 算法后,看看效果如下所示:
通过上面两幅图的数据对比,可以看到Draw Call明显减少了,优化效果还是非常明显的,再看看另一种Occlusion Culling 算法实现的效果。
IOC算法
先把该算法能实现的功能给读者介绍一下:
1、实现建筑物的裁剪
2、粒子效应遮挡剔除
3、灯光遮挡剔除
4、完全支持实时阴影
5、完全支持动态批处理
6、支持移动设备上的密集场景处理
我们先看看对特效的遮挡剔除优化,在优化前的场景渲染,如下图所示:
优化后的遮挡剔除效果,如下图所示:
通过两幅图对比可以看到,Draw Call减少了一半多,当然我们还可以进一步去优化。
该算法对于密集型建筑同样好用,同样先展示一个没有使用任何裁剪算法的有密集物体的场景,Draw Call数量是非常大的。如下图所示:
经过我们的Occlusion Culling算法后的裁剪效果,如下图所示:
Draw Call数量对比也是非常明显的,还是有效果的。
总结:
以上给读者介绍了针对密集型建筑使用的解决方案,该方法在PC端,移动端都是适用的,最后把代码奉上,参考案例代码可以将其应用到自己的项目开发中。
代码下载地址:
链接:https://pan.baidu.com/s/1Uhp-eejG_7rA_hXz42cBVg 密码:5ehf
参考网址:
https://blogs.unity3d.com/cn/2018/01/12/unity-labs-autolod-experimenting-with-automatic-performance-improvements/