程序丨如何把WebGL显存占用减少84.2%?
Posted 腾讯GWB游戏无界
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了程序丨如何把WebGL显存占用减少84.2%?相关的知识,希望对你有一定的参考价值。
H5游戏端的性能优化包括几个方向:物理内存,帧耗时,GPU内存(显存)等等。这些指标占用越低,游戏运行就越流畅,现在就讲讲空间宠物spine动画的显存优化,另外我也会把中间遇到的每个知识点都深入解释清楚,当做福利送给大家。
上一篇介绍完一系列优化方案(传送门:),包括物理内存(拆分动作json文件),帧耗时(canvas2D渲染时独立背景部分到dom节点上),GPU内存(及时销毁内存)等等方案之后游戏也能流畅稳定的运行在上千万的用户手机端了。不过作为前端开发,必须折腾不止,将游戏更好地呈现给用户,占用用户更少的资源,用有限的资源干更多的事情!现在讲讲我们的GPU内存优化三十六计。
第一章——想法诞生:显存优化三十六计之开源节流
每个机器的显存大小都是有限,想做字面意思上的开源并不是我们webview应用层能干的事情,不过可以换种思路,就是申请新的显存的时候,看看旧的显存是不是可以释放而减少剩余显存的申请,让总体占用的显存维持在一个比较低而稳定的数值,而不是递增。上一篇我们已经简单做了一些措施,为什么说简单,我觉得还远远不够,得继续深入研究。现在就讲讲我们对于节流的研究:
节流:游戏中跟GPU相关的概念是texture(纹理),也就是图片。要想节流就必须最大限度的减少图片的尺寸。
第二章——深入分析:显存优化三十六计之知己知彼
分析了一下空间模型里面的页面(打包的时候会把所有的图片生成一张大的雪碧图,这里统一就叫页面)发现有大面积的透明区域,主要是:
一、2的幂数的影响:因为是三端共用的模型,客户端用的是cocos2d游戏引擎,他们需要图片必须是2的幂数,这就造成为了凑足1024,2048这样的尺寸导致透明区域很多,约占40%
解释下:
2的幂数是为了迎合一项技术:mipmap(为了加快渲染速度和减少图像锯齿,贴图被处理成由一系列被预先计算和优化过的图片组成的文件),在WebGL读取纹理之前,设置了需要mipmap处理,WebGL代码为:
就会先把图片按2的倍数逐渐缩小7张图片,并且缓存起来,如下图:
从而在图片与视点距离切换的时候,webgl能最快地给到该物体与眼睛的距离下,跟已经缓存的8张图片中大小最接近的图片(都已经缓存啦,肯定快,而且都是2的幂数,等比缩放,也没有变形锯齿),对于怎么寻找最接近的图片也是有一套算法的,这里就不展开了。这样分析下来,mipmap优缺点就显而易见了:
缺点:会占用内存,因为mipmap会根据摄像机远近不同而生成对应的七个贴图,所以必然占内存!
优点:会优化显存带宽,用来减少渲染,因为可以根据实际情况,会选择适合的贴图来渲染,距离摄像机越远,显示的贴图像素越低,反之,像素越高!
为了视角发生变化的时候更加流畅(跑酷类游戏中人物跳跃,奔跑的时候都会有一些放大缩小,来表达距离的远近,从而2d也能有些3d的效果)
有些引擎,特别是3d引擎,他,mipmap是必选项,如果是非2幂的图片,会先强行拉伸转化成2的幂数,这就造成变形,这样肯定不行!
大多数时候,适合你的才是最好的。先分析下我们游戏的现状。
1.游戏比较特殊,目前交互简单,纯2d展示,并没有距离的变化,生成这么多mipmap内存占用确实有点浪费
2.H5选择的spine引擎并不强制使用2的幂数,它会识别图片的尺寸,如果是非2幂的就不mipmap了
有这样2点基本条件,就可以关掉2的幂数的勾选了,减少了很大一部分原始页面的透明区域以及生成mipmap会多出来的7份缓存。
二、装扮类的图片,因为最初的模型都是没有装扮的,所以原始页面这部分全部都是透明的。约占60%
脑洞大开:装扮类别的既然都是空白的,就不需要打包在原始页面(大雪碧图)里,由前端自己生成这个图片。声明同等大小的空白canvas来做装扮类的图片。60%的空白全部缩减。现在就有两个问题:
1.如何把原始大页面中的装扮类透明区域去掉
2.如何在图集(.atlas)中带上装扮类的尺寸,好让前端页面能够用一个canvas代替
小结:较少纹理的尺寸在于减少纹理中的透明区域,2的幂数以及装扮图片是造成透明区域的源头。而非2的幂数可以不使用mipmap,也进一步较少了GPU内存的占用
第三章——实现:显存优化三十六计之借力打力
为了避免重复造轮子,肯定先找有没有现成的工具把一张图片中的透明区域抠掉。后面想到spine编辑器的导出工具是否支持这样的功能。
在此之前先详细介绍一下spine编辑器导出的参数介绍,和官网雷同的地方就不赘述了。这里只讲经常要用到的导出json和打包图集(可单独打包图集的哦,参数设置和导出json时候是同一套)
1.导出json的参数,较为简单
非必要的数据:勾选时, JSON 将包含那些渲染骨架所不必需的额外数据,使得文件略大。不过 JSON 导回 Spine 时需要此类数据。试了一下500多KB的json文件能少10KB左右
优质打印:导出的时候会格式化json格式,会有很多空格和换行,如果在外网读取的话还是不要勾选这个选项,可以减少文件大小
2.图集打包器参数(可单独使用)
去除x/y轴空白区,为了减少导出的页面尺寸,每张图片在页面的尺寸会比实际尺寸要小,图片的四边的空白区域会被裁剪,可以通过orig,size,offset这三个值还原实际图片。勾选这个值竟然就可以去掉页面中所有的空白区域,大小都会变成1*1,问题一搞定
其余参数的说明见文章最后
总结一下,我们可以通过SPINE编辑器的导出工具来实现扣去页面上所有的透明区域,那接下来就剩怎么利用这张被阉割的页面去正常的展示和换装了。
这样导出的图集直接可以正常的展示,换装就有问题,换装的含义就是替换同名附件的图片纹理,其中有两类换装方式:
(1)图片类型的附件换装,直接就可以换,使用的是引擎自带的换装接口
(2)mesh类型的附件:因为需要绑定顶点和三角形区域,再绘制纹理。自带的换装接口无用。最优的方案是先用一个透明的canvas占位,绑定好顶点和三角区域之后,换装则是把新图片画到以前的canvas上,再update一下这个纹理即可,流程如下:
a.读取atlas => b.生成该装扮图片一样大小(数据缺失)的canvas => c.生成前端模型 => d.换装是把装扮图片drawImage到canvas上 => e.update纹理
整个流程分析下来需要mesh类型附件图片的大小参数,这个就可以通过自己写的工具从完整的图集数据里面读取出来,生成如下的一份图集配置
注:a.第一行必须是空格 b.size要设置成装扮图片的大小。
第四章——优化结果
眼见为实,下面是在chrome上的测试结果:
实验条件:初始显存一样,分别加载优化前的模型数据和优化后的模型数据,对比GPU内存增量
实验数据:初始显存 :42265K
实验结果:
(1)优化前的模型,显存增量:58199 - 42265 = 15934KB
(2)优化后的模型,显存增量:44739 - 42265 = 2474KB
实验结论:一只模型占用的显存从15.9MB下降到2.5MB,下降了84.2%
经过理性的分析,GPU内存是肯定有显著的下降的因为:
(1)透明区域没有了,图片尺寸减小了很多。纹理申请的GPU内存计算方式是:内存大小=宽*高*4+... 宽高减少了之后内存就会下降
(2)非2的幂数不会启用mipmap,不需要预缓存的7张不同尺寸的纹理,减少了GPU内存占用。
-----分割线,接上面导出参数介绍部分-----
旋转:导出的时候图片可以90度旋转,从而打包工具可以计算得出最佳的雪碧图排版方式,生成的页面最小,引擎一般都是支持rotate属性的
别名:像素相同的只打包一次,也可以减少一定的透明区域,但是不够彻底
忽略空白图片:透明图和其附件都会被忽略,不在图集文件里面显示,这个比较危险,不建议勾选
页面类(就是通俗意义上的雪碧图)
最大宽/高度:限制了之后,可能会生成多张页面,引擎也是支持的哈
2的幂数:刚刚分析篇就已经介绍了,mipmap的需要,有些客户端引擎必须要勾选这个属性,不然纹理会变形,而且如果模型有距离变化的时候最好勾选上。否则不勾选可以节约内存,但必须要引擎支持
区域填充(重要)
填充X/Y/边缘:填充到图片和图片之间的px值和边缘的空白px值,不添加一些空白区域的话,渲染的时候可能会出现这样的问题:
预乘alpha:合成的效能更高,实现正确的透明效果,减少锯齿的出现,这里需要注意的是需要渲染引擎也需要支持这种格式,不然会显示成这样:会有黑边
运行时:
包裹X/Y:ClampToEdge,Repeat,MirrorRepeat三种模型,pixi规定在用Repeat,MirrorRepeat这两种模式需要先支持mipmap。这个概念有点像css的repeat属性。clamptoedge相当于no-repeat。具体示例图如下:
今日推荐
添加小编微信,可享双重福利
1.加入GAD程序猿交流基地
获取行业干货资讯,观看大牛分享直播
包括腾讯内部分享、文章教程、视频教程等全套资料
↓长按添加小编GAD苏苏↓
以上是关于程序丨如何把WebGL显存占用减少84.2%?的主要内容,如果未能解决你的问题,请参考以下文章