原文https://blog.csdn.net/u010223072/article/details/78287294

理论要点

要点一: 
文件格式与像素格式的区别:文件格式是图像为了存储信息而使用的对信息的特殊编码方式,大都经过了压缩,它存储在磁盘或内存中,但是并不能被GPU所识别(jpg,png…),这些图片格式当被游戏读入后,还需要经过CPU解压成像素格式,如:RGBA8888,再传送到GPU端进行使用。 
而像素格式是能被GPU所识别的,能被快速寻址并采样。

要点二: 
图片本身大小和其所占内存大小是两码事。这就好比一个zip压缩包使用时要解压还原数据,这个zip文件就好比图片本身,而解压后的文件就好比图片所占内存大小。纹理本身大小主要看我们选用什么样的压缩格式和压缩比,而所占内存大小就只由两个因素决定:1,图片的像素点个数(分辨率) 2,单位像素占用的字节数(像素格式)。即纹理内存大小 = 纹理长度 * 纹理宽度 * 单位像素占用的字节数,如:一张1136x640的RGBA8888的png图片占用的内存为 1136x640x4 = 2.8M左右。 
注:cocos引擎中,对于大的背景图我们一般使用jpg文件格式,jpg压缩比更大,是有损压缩,而像素格式使用16位的RGB565格式。但是它占内存大小就不是我们使用的RGB565 16位格式了,cocos会自动把它转换为RGBA8888 32位格式解析。最终决定图片占用内存的是它的像素格式和尺寸,与其扩展名无关。png8、png32、jpg、pvr只要其像素格式都是rgba8888,那么最终图片占用的内存是一样的。

要点三: 
在cocos中,谈谈不同纹理实际加载过程中内存变化,先以一张1024*1024 本身大小500k的jpg/png图片为例: 
1,读取图片文件(500k) 
2,把jpg/png数据最终都是按RGBA8888(默认)格式解析(4mb) 
3,释放500k的图片内存 
4,上传给OpenGL纹理数据(4mb) 
5,释放4mb内存 
注意,这个过程不是必然的顺序执行,释放内存实际是由系统决定的,会很快,但是不一定是立即执行。 所以内存会瞬间飙升到8.5mb左右,然后减少5mb,稳定到4mb左右,这么一个过程变化。这就是我们常说的“间歇性内存飙高”。

而pvr格式显卡直接支持,加载速度自然要快,不需要开辟临时内存来读取pvr图片,节约了解析图片数据到纹理这一步的消耗(第2步)。也就是说读取同样像素格式的pvr资源(一般用pvr.ccz压缩格式)消耗4mb,将pvr图片数据提交给显卡消耗4mb。然后释放文件数据4mb。这么看似乎跟Png从内存占用上相比也没什么优势。但是如果像素格式用的是RGBA4444那就有很大优势了,内存少一半。而前面的那种自身不管用什么格式,最终cocos都会把它们的格式统一默认转换为32位的RGBA8888再上传GPU。 
注释: 
1,pvr.ccz其实就是pvr图片zip打包下,程序读的时候要先解压出pvr资源,然后再读取pvr。不过由于压缩下可以极大的减小图片体积,所以虽然多了解压过程也不会有特别多的cpu消耗,一般我们都是推荐选择pvr.ccz的。 
2,当加载jpg、png这样的纹理时,在短时候内,它会消耗约两倍于(jpg3倍,多jpg到png转换过程)它本身内存占用的内存大小。这个告诉我们这样的纹理最好不要一帧内连续加载,最好分散到多帧去完成,因为每帧cocos都会自动回收一次内存,对于这些中间创建的纹理内存会自动释放,从而避免一帧里内存不至于飙太高。 
3,按照纹理size从大到小的顺序加载纹理,由于加载纹理时额外的内存消耗问题,所以,采用按纹理size从大到小的方式来加载纹理是一个最佳实践。假设,你有一个占内存16MB的纹理和四个占用内存4MB的纹理。如果你首先加载4MB的纹理,这个程序将会使用16MB的内存,而当它加载第四张纹理的时候,短时间内会飙到20MB。这时,你要加载16MB的那个纹理了,内存会马上飙到48MB(4*4 + 16*2),然后再降到32MB(4*4 + 16)。但是,反过来,你先加载16MB的纹理,然后短时候内飙到32MB。然后又降到16MB。这时候,你再依次加载剩下的4个4MB的,这时,最多会彪到(4*3 + 4*2 + 16=36)MB。在这两种情况下,内存的峰值使用相差12MB,要知道,可能就是这12MB会断送你的游戏进程的小命。

如何减小资源占磁盘大小

1,jpg压缩比最高,质量较好,但是不支持半透明(一般用于背景图)。 
2、png8同样图片会比jpg略大一些,使用ImageAlpha进行转换,视觉上几乎看不出差别。 
注: 这两种图片格式都可以极大的减少图片体积(减少70%~80%),但是无助于减少内存。

如何减小资源占内存大小

1,尽量使用颜色深度为16bit的图片。cocos上通过cc.Texture2D.setDefaultAlphaPixelFormat(cc.Texture2D.PIXEL_FORMAT_RGBA4444)改变默认像素格式,但如果图片本身的颜色深度是32位,转换成RGBA4444后,则可能会使图片失真,看起来就很模糊。这个可以通过TexturePacker工具中开启抖动算法得到改善(模糊处颜色混合处理)。特别是在拥有Retina显示的像素密度下,你几乎看不出16位与32位的纹理之间的差别。

2,碎图打大图时,使用NPOT纹理,NOPT是“non power of two”的缩写,译作“不是2的幂”。如果纹理图集(texture atlas)使用NPOT的纹理,它将有一个具大的优势:它允许TexturePacker更好地压缩纹理。因此,我们会更少地浪费纹理图集的空白区域。而且,这样的纹理在加载的时候,会少使用1%到49%左右的内存。

3,使用pvr格式纹理。因为jpg是没有透明色的,一个像素最多3字节,而png一个像素4字节,jpg纹理应该占用内存更小才对,但是cocos最终把纹理都会转换成rgba8888格式,所以无论是jpg还是png,一个像素占用的都是4字节。正因cocos2d对其他纹理支持不够好,pvr才会显得那么高效。pvr也不是万金油。pvr图像是专门为ios设备上面的powerVR图形芯片指定的图形容器,可以直接加载到显卡上,而不需经过中间的转化。虽然android设备下可以使用pvr格式,但是不能使用pvrtc4(一个像素只占4bit),希望通过pvr像ios设备上一样真正减少游戏内存是不太可行的。

4,android上最省内存纹理当然是ETC(一个像素占4bit),不过ETC1没有alpha通道,需要我们额外通过一些简单shader实现(同样大小的遮罩图做颜色混合)。不过现在最新的ETC2可以直接支持alpha通道了,而且效果更好,但是需要opengles3.0支持,考虑到2.0设备的市场占有率,一般使用ETC1。

实际项目中纹理格式选择

人生之所以纠结,在于许多事情你可以选择。上面的纹理格式,同一种情况下,可能多种都适合,那如何选择呢!我们还是根据具体情况而定: 
1、场景、背景、全屏图片 
2D手机游戏中,多半都有这样的图片,以作为背景,特别在一些SLG,横版过关游戏中。这种图片对ALPHA没有要求,并且,在同一时间,只会出现一张(如果是多张拼接,也不会超过屏幕尺寸太多),内存不会成为关键点。所以,在这种情况下,我们大胆选择JPG就可以了。

2、场景的前景,装饰物,可移动对象(npc,moster,…) 
这种要看规模,如果规模较小,类型不多。 或者类型虽然多,但同一时间出现在场景中的类型不多,那我们可以选择压缩PNG8的方式,它支持ALPHA通道,文件又小。如果同屏可能出现多种这种,则需要考虑在IOS上使用PVRTC,在ANDROID上使用ETC1+ALPHA_MASK。实际上,为了好维护,一般都是统一用pvr.ccz打包。

3、UI 
UI的背景图,可以优先考虑使用压缩PNG8,如果达不到精度要求,则使用PNG32。而对于UI的小元素,可以考虑使用压缩PNG8. 
对于UI的图标,一般是不带ALPHA的PVRTC/ETC + 一张公共的ALPHA掩码图,通过双层混合来实现圆边效果。 因为图标同屏出现可能较大。 如果图标能够控制在一定范围内,由于图标是48X48等大小,一张1024x1024的大图,可以放400个图标。 换用JPG,也有4MB的开销,如果这个是可以接受的,也可以使用JPG+ALPHA_MASK的方式。

写到这里才发现,其实只需要下面一句话就可以搞定。 
这类图片会不会同时出现多个,同时出现时,内存开销是否无法接受, 如果确实无法接受,则使用GPU纹理,否则,优先考虑JPG,JPG+ALPHA,或者PNG8。就是说,首先要减小安装包大小,如果内存有无法接受的情况,才需要用GPU纹理进行优化。

经验总结

游戏内存优化我们一般可以从这么3个方面入手:引擎自身提供的优化选项,引擎底层框架,语言上层(内存泄漏)。 
下面是一些常用手段: 
首先看纹理优化,为了优化纹理内存使用,必须知道什么因素对纹理内存使用的影响最大。主要有3个因素会影响纹理内存,即纹理格式(压缩还是非压缩)、颜色深度和大小。我们可以使用PVR格式纹理减少内存使用。推荐纹理格式为pvr.ccz。纹理使用的每种颜色位数越多,图像质量越好,但是越耗内存。所以我们可以使用颜色深度为RGB4444的纹理代替RGB8888,这样内存消耗会降低一半。此外超大的纹理也会导致内存相关问题。所以最好使用中等大小的纹理。 
音频优化,3个因素会影响音频文件的内存使用,即音频文件数据格式、比特率及采样率。推荐使用MP3数据格式的音频文件,因为Android平台和iOS平台均支持MP3格式,此外MP3格式经过压缩和硬件加速。背景音乐文件大小应该低于800KB,最简单的方法就是减少背景音乐时间然后重复播放。音频文件采样率大约在96-128kbps为佳,比特率44kHz就够了。 
字体和粒子优化,在此有两条小提示:使用BMFont字体显示游戏分数时,请尽可能使用最少数量的文字。例如只想要显示单位数的数字,你可以移除所有字母。至于粒子,可以通过减少粒子数来降低内存使用。

提示与技巧: 
1、一帧一帧载入游戏资源 
2、减少绘制调用,打包大图 
3、载入纹理时按照从大到小的顺序 
4、避免高峰内存使用 
5、使用载入屏幕预载入游戏资源 
6、需要时释放空闲资源 
7、收到内存警告后释放缓存资源 
8、使用纹理打包器优化纹理大小、格式、颜色深度等 
9、使用JPG格式要谨慎! 
10、请使用RGB4444颜色深度16位纹理 
11、请使用NPOT纹理,不要使用POT纹理 
12、避免载入超大纹理 
13、推荐1024*1024 NPOT pvr.ccz纹理集,而不要采用RAW PNG纹理

Cocos纹理理解的更多相关文章

  1. 2018-10-20-C#-从零开始写-SharpDx-应用-初始化dx修改颜色

    title author date CreateTime categories C# 从零开始写 SharpDx 应用 初始化dx修改颜色 lindexi 2018-10-20 17:34:37 +0 ...

  2. C# 从零开始写 SharpDx 应用 初始化dx修改颜色

    原文:C# 从零开始写 SharpDx 应用 初始化dx修改颜色 版权声明:博客已迁移到 https://blog.lindexi.com 欢迎访问.如果当前博客图片看不到,请到 https://bl ...

  3. 我所理解cocos2d-x 3.6 lua --使用Cocos Studio

    Cocos是触控科技推出的游戏开发一站式解决方案,包含了从新建立项.游戏制作.到打包上线的全套流程. 开发者可以通过cocos快速生成代码.编辑资源和动画,最终输出适合于多个平台的游戏产品. Coco ...

  4. Android OpenGL ES(七)----理解纹理与纹理过滤

    1.理解纹理 OpenGL中的纹理能够用来表示图像.照片,甚至由一个数学算法生成的分形数据.每一个二维的纹理都由很多小的纹理元素组成.它们是小块的数据,类似于我们前面讨论过的片段和像素.要使用纹理,最 ...

  5. cocos基础教程(10)纹理缓存技术

    Cocos2d通过调用CCTextureCache或者CCSpriteFrameCache来缓存精灵的纹理. 当这个精灵调用CCTextureCache 或 CCSpriteFrameCache的方法 ...

  6. Cocos_Code_Ide学习(一):理解Cocos Lua Project下的frameworks的proj.win32

    第一次写,不知道有没有用,有不对的地方,接受大家的批评.勿喷,谢谢. 1.首先,创建工程 ------------------------------------------------------- ...

  7. DirectX11--深入理解与使用2D纹理资源

    前言 写教程到现在,我发现有关纹理资源的一些解说和应用都写的太过分散,导致连我自己找起来都不方便.现在决定把这部分的内容整合起来,尽可能做到一篇搞定所有2D纹理相关的内容,其中包括: DDSTextu ...

  8. cocos creator 入门理解点

    简单解释, [来源:官方文档] Cocos是触控科技推出的游戏开发一站式解决方案,包含了从新建立项.游戏制作.到打包上线的全套流程.开发者可以通过cocos快速生成代码.编辑资源和动画,最终输出适合于 ...

  9. 我所理解的Cocos2d-x

    我所理解的Cocos2d-x(完全基于Cocos2d-x3.0,深度剖析计算机图形学,OpenGL ES及游戏引擎架构,全面提升游戏开发相关知识) 秦春林 著   ISBN 978-7-121-246 ...

随机推荐

  1. css的多级分类

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  2. UltraEdit设置打开的文件类型,怎么打开大文本文件

    点击高级,配置,选择文件处理下的临时文件,设置如图即可打开超大文本文件. 补充:视图——显示行号.

  3. js实现汉字转拼音

    汉字转拼音,每个字首字母大写:pinyin.getFullChars(name); 提取首字母并大写:pinyin.getCamelChars(name); /* --- description: P ...

  4. React的React.createElement源码解析(一)

    一.什么是jsx  jsx是语法糖  它是js和html的组合使用  二.为什么用jsx语法 高效定义模版,编译后使用 不会带来性能问题 三.jsx语法转化为js语法  jsx语法通过babel转化为 ...

  5. ubuntu的dpkg命令安装和卸载软件

    实际使用中,可以先到网上下载deb文件,然后用dpkg命令来安装. sudo dpkg -l | grep 360 #查看包含360的软件sudo dpkg -i browser360-cn-stab ...

  6. Petr and a Combination Lock

    Petr has just bought a new car. He's just arrived at the most known Petersburg's petrol station to r ...

  7. SQL语句 分组 多行合并成一行

    ,,'')) FROM Table d GROUP by Id 另外: sql 单引号转义:两个单引号转义为一个单引号 set @sql='STUFF((SELECT '','' + Names FR ...

  8. Laravel 图片无法显示的问题

    无法显示图片 先跳转到指定目录 mklink /d storage d:\www\dev.hanwen.com\storage\app

  9. 探讨LoadRunner的并发用户和集合点

    近来跟踪一个项目,发现同事们在执行性能测试时,比较热衷于使用集合点,从概念上认为要得到并发用户就必须设置集合点,认为在执行一个压力测试脚本时,设置了集合点才算是有效的并发用户,没有设置结合点,就认为可 ...

  10. flask使用websocket

    # flask使用websocket 1.概述 flask实现websocket有两种方式:flask_sockets,Flask-SocketIO. flask_sockets:该方式是flask对 ...