程序丨如何把WebGL显存占用减少84.2%?

Posted 腾讯GWB游戏无界

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了程序丨如何把WebGL显存占用减少84.2%?相关的知识,希望对你有一定的参考价值。

H5游戏端的性能优化包括几个方向:物理内存,帧耗时,GPU内存(显存)等等。这些指标占用越低,游戏运行就越流畅,现在就讲讲空间宠物spine动画的显存优化,另外我也会把中间遇到的每个知识点都深入解释清楚,当做福利送给大家。


上一篇介绍完一系列优化方案(传送门:),包括物理内存(拆分动作json文件),帧耗时(canvas2D渲染时独立背景部分到dom节点上),GPU内存(及时销毁内存)等等方案之后游戏也能流畅稳定的运行在上千万的用户手机端了。不过作为前端开发,必须折腾不止,将游戏更好地呈现给用户,占用用户更少的资源,用有限的资源干更多的事情!现在讲讲我们的GPU内存优化三十六计。


第一章——想法诞生:显存优化三十六计之开源节流


每个机器的显存大小都是有限,想做字面意思上的开源并不是我们webview应用层能干的事情,不过可以换种思路,就是申请新的显存的时候,看看旧的显存是不是可以释放而减少剩余显存的申请,让总体占用的显存维持在一个比较低而稳定的数值,而不是递增。上一篇我们已经简单做了一些措施,为什么说简单,我觉得还远远不够,得继续深入研究。现在就讲讲我们对于节流的研究:


节流:游戏中跟GPU相关的概念是texture(纹理),也就是图片。要想节流就必须最大限度的减少图片的尺寸。


第二章——深入分析:显存优化三十六计之知己知彼


分析了一下空间模型里面的页面(打包的时候会把所有的图片生成一张大的雪碧图,这里统一就叫页面)发现有大面积的透明区域,主要是:


程序丨如何把WebGL显存占用减少84.2%?


一、2的幂数的影响:因为是三端共用的模型,客户端用的是cocos2d游戏引擎,他们需要图片必须是2的幂数,这就造成为了凑足1024,2048这样的尺寸导致透明区域很多,约占40%


解释下:


2的幂数是为了迎合一项技术:mipmap(为了加快渲染速度和减少图像锯齿,贴图被处理成由一系列被预先计算和优化过的图片组成的文件),在WebGL读取纹理之前,设置了需要mipmap处理,WebGL代码为:


程序丨如何把WebGL显存占用减少84.2%?


就会先把图片按2的倍数逐渐缩小7张图片,并且缓存起来,如下图:


程序丨如何把WebGL显存占用减少84.2%?


从而在图片与视点距离切换的时候,webgl能最快地给到该物体与眼睛的距离下,跟已经缓存的8张图片中大小最接近的图片(都已经缓存啦,肯定快,而且都是2的幂数,等比缩放,也没有变形锯齿),对于怎么寻找最接近的图片也是有一套算法的,这里就不展开了。这样分析下来,mipmap优缺点就显而易见了:


缺点:会占用内存,因为mipmap会根据摄像机远近不同而生成对应的七个贴图,所以必然占内存!


优点:会优化显存带宽,用来减少渲染,因为可以根据实际情况,会选择适合的贴图来渲染,距离摄像机越远,显示的贴图像素越低,反之,像素越高!


为了视角发生变化的时候更加流畅(跑酷类游戏中人物跳跃,奔跑的时候都会有一些放大缩小,来表达距离的远近,从而2d也能有些3d的效果)


程序丨如何把WebGL显存占用减少84.2%?


有些引擎,特别是3d引擎,他,mipmap是必选项,如果是非2幂的图片,会先强行拉伸转化成2的幂数,这就造成变形,这样肯定不行!


大多数时候,适合你的才是最好的。先分析下我们游戏的现状。


1.游戏比较特殊,目前交互简单,纯2d展示,并没有距离的变化,生成这么多mipmap内存占用确实有点浪费


2.H5选择的spine引擎并不强制使用2的幂数,它会识别图片的尺寸,如果是非2幂的就不mipmap了


程序丨如何把WebGL显存占用减少84.2%?


有这样2点基本条件,就可以关掉2的幂数的勾选了,减少了很大一部分原始页面的透明区域以及生成mipmap会多出来的7份缓存。


二、装扮类的图片,因为最初的模型都是没有装扮的,所以原始页面这部分全部都是透明的。约占60%


脑洞大开:装扮类别的既然都是空白的,就不需要打包在原始页面(大雪碧图)里,由前端自己生成这个图片。声明同等大小的空白canvas来做装扮类的图片。60%的空白全部缩减。现在就有两个问题:


1.如何把原始大页面中的装扮类透明区域去掉

2.如何在图集(.atlas)中带上装扮类的尺寸,好让前端页面能够用一个canvas代替


小结:较少纹理的尺寸在于减少纹理中的透明区域,2的幂数以及装扮图片是造成透明区域的源头。而非2的幂数可以不使用mipmap,也进一步较少了GPU内存的占用


第三章——实现:显存优化三十六计之借力打力


为了避免重复造轮子,肯定先找有没有现成的工具把一张图片中的透明区域抠掉。后面想到spine编辑器的导出工具是否支持这样的功能。


在此之前先详细介绍一下spine编辑器导出的参数介绍,和官网雷同的地方就不赘述了。这里只讲经常要用到的导出json和打包图集(可单独打包图集的哦,参数设置和导出json时候是同一套)


1.导出json的参数,较为简单


程序丨如何把WebGL显存占用减少84.2%?


非必要的数据:勾选时, JSON 将包含那些渲染骨架所不必需的额外数据,使得文件略大。不过 JSON 导回 Spine 时需要此类数据。试了一下500多KB的json文件能少10KB左右


优质打印:导出的时候会格式化json格式,会有很多空格和换行,如果在外网读取的话还是不要勾选这个选项,可以减少文件大小


2.图集打包器参数(可单独使用)


程序丨如何把WebGL显存占用减少84.2%?


去除x/y轴空白区,为了减少导出的页面尺寸,每张图片在页面的尺寸会比实际尺寸要小,图片的四边的空白区域会被裁剪,可以通过orig,size,offset这三个值还原实际图片。勾选这个值竟然就可以去掉页面中所有的空白区域,大小都会变成1*1,问题一搞定


程序丨如何把WebGL显存占用减少84.2%?


其余参数的说明见文章最后


总结一下,我们可以通过SPINE编辑器的导出工具来实现扣去页面上所有的透明区域,那接下来就剩怎么利用这张被阉割的页面去正常的展示和换装了。


这样导出的图集直接可以正常的展示,换装就有问题,换装的含义就是替换同名附件的图片纹理,其中有两类换装方式:


程序丨如何把WebGL显存占用减少84.2%?


(1)图片类型的附件换装,直接就可以换,使用的是引擎自带的换装接口


(2)mesh类型的附件:因为需要绑定顶点和三角形区域,再绘制纹理。自带的换装接口无用。最优的方案是先用一个透明的canvas占位,绑定好顶点和三角区域之后,换装则是把新图片画到以前的canvas上,再update一下这个纹理即可,流程如下:


a.读取atlas => b.生成该装扮图片一样大小(数据缺失)的canvas => c.生成前端模型 => d.换装是把装扮图片drawImage到canvas上 => e.update纹理


整个流程分析下来需要mesh类型附件图片的大小参数,这个就可以通过自己写的工具从完整的图集数据里面读取出来,生成如下的一份图集配置


程序丨如何把WebGL显存占用减少84.2%?


注:a.第一行必须是空格  b.size要设置成装扮图片的大小。


程序丨如何把WebGL显存占用减少84.2%?


第四章——优化结果


眼见为实,下面是在chrome上的测试结果:


实验条件:初始显存一样,分别加载优化前的模型数据和优化后的模型数据,对比GPU内存增量


实验数据:初始显存 :42265K


实验结果:


(1)优化前的模型,显存增量:58199 - 42265 = 15934KB


程序丨如何把WebGL显存占用减少84.2%?


(2)优化后的模型,显存增量:44739 - 42265 = 2474KB


程序丨如何把WebGL显存占用减少84.2%?


实验结论:一只模型占用的显存从15.9MB下降到2.5MB,下降了84.2%


经过理性的分析,GPU内存是肯定有显著的下降的因为:


(1)透明区域没有了,图片尺寸减小了很多。纹理申请的GPU内存计算方式是:内存大小=宽*高*4+...  宽高减少了之后内存就会下降


(2)非2的幂数不会启用mipmap,不需要预缓存的7张不同尺寸的纹理,减少了GPU内存占用。


-----分割线,接上面导出参数介绍部分-----


程序丨如何把WebGL显存占用减少84.2%?


旋转:导出的时候图片可以90度旋转,从而打包工具可以计算得出最佳的雪碧图排版方式,生成的页面最小,引擎一般都是支持rotate属性的


别名:像素相同的只打包一次,也可以减少一定的透明区域,但是不够彻底


忽略空白图片:透明图和其附件都会被忽略,不在图集文件里面显示,这个比较危险,不建议勾选


页面类(就是通俗意义上的雪碧图)


最大宽/高度:限制了之后,可能会生成多张页面,引擎也是支持的哈


2的幂数:刚刚分析篇就已经介绍了,mipmap的需要,有些客户端引擎必须要勾选这个属性,不然纹理会变形,而且如果模型有距离变化的时候最好勾选上。否则不勾选可以节约内存,但必须要引擎支持


区域填充(重要)


填充X/Y/边缘:填充到图片和图片之间的px值和边缘的空白px值,不添加一些空白区域的话,渲染的时候可能会出现这样的问题:


程序丨如何把WebGL显存占用减少84.2%?


预乘alpha:合成的效能更高,实现正确的透明效果,减少锯齿的出现,这里需要注意的是需要渲染引擎也需要支持这种格式,不然会显示成这样:会有黑边


程序丨如何把WebGL显存占用减少84.2%?


运行时:


包裹X/Y:ClampToEdge,Repeat,MirrorRepeat三种模型,pixi规定在用Repeat,MirrorRepeat这两种模式需要先支持mipmap。这个概念有点像css的repeat属性。clamptoedge相当于no-repeat。具体示例图如下:


程序丨如何把WebGL显存占用减少84.2%?


程序丨如何把WebGL显存占用减少84.2%?

今日推荐




添加小编微信,可享双重福利

1.加入GAD程序猿交流基地

获取行业干货资讯,观看大牛分享直播

包括腾讯内部分享、文章教程、视频教程等全套资料

 

↓长按添加小编GAD苏苏↓

程序丨如何把WebGL显存占用减少84.2%?

以上是关于程序丨如何把WebGL显存占用减少84.2%?的主要内容,如果未能解决你的问题,请参考以下文章

Linux--无进程却显示占用显存,GPU显存释放方法

关于tensorflow的显存占用问题

如何正确统计C程序运行的内存占用量?

GPU 显存释放

游戏开发面试准备8(虚拟内存,c++ override,用户态内核态,显存内存缓存)

科普帖:深度学习中GPU和显存分析