Cocos2dx 版本: 3.10
CocosCreator 版本: 3.8.0
环境: Mac
简介
在项目开发中,图片资源的优化是作为性能优化和包体优化的一项重要侧露。常用的手段有:
-
使用TexturePacker将散图打包图集
-
JPG
和PNG
的使用,从包体来说JPG
更小,从性能来说PNG
更快 -
使用压缩纹理对游戏进行打包,Android的
ETC
,IOS的PVRTC
等
在这里面已经涉及到对纹理的理解,比如来说:
- 关于TexturePacker工具里面的参数设定
- 关于cocos2dx引擎对纹理
Texture2D
的封装使用 - 关于cocosCreator对
ImageAsset
资源下的Texture
的参数设定 - 关于使用OpenGL ES 渲染中锯齿的出现原因
这些都跟纹理挂钩, 了解纹理有助于我们做更好的游戏。
对我而言,纹理是一个让人很惧怕的词汇。
在刚入行的时候我不知道它到底代表着什么,入行cocos2dx以后,了解到渲染,了解到OpenGL ES, 我才对纹理有所了解。 再遇到现在的cocosCreator ,我觉得应该根据自己对纹理的了解将技术分享出来。
可能有所误解,希望看到的小伙伴能进行反馈,共同学习和成长, 感谢!
基础概念
在开始之前,以cocos2dx 2D为例,简要说明下渲染的流程, 这对于后面的理解纹理格式是有帮助的。
如果有小伙伴想详细的了解cocos2dx的渲染流程,可参考我之前写的博客:
cocos2d-x 渲染机制简介
cocos2d-x 绘制命令
cocos2d-x OpenGL ES 简介
纹理是实现渲染的重要基础。
我们会将JPG
或PNG
的不同格式的图像资源放置在项目中,引擎会针对于不同的图像格式通过CPU转换为RGB
或者RGBA
的纹理格式,纹理格式被GPU用来读取获取纹理数据,并借助于OpenGL ES对纹理数据进行采样,将采样数据交给片段着色器着色,从而完成渲染的目的。
这里需要我们注意几个概念:
图像
指的是JPG,PNG,GIF,JPEG
等图片资源,采用特殊编码生成的存储格式,用于传输和存储图像信息。
纹理
分为未压缩纹理和压缩纹理两类,它主要被OpenGL用来采样获取纹理数据进行渲染
纹理像素
以JPG
为例,在图片放大以后发现由多个像素点组成,这个像素点就叫做纹理像素, 也被称为纹素。
每个像素点由RGB
或RGBA
组成,不同的像素数值组成一幅彩色的图像。
采样
它主要在OpenGL渲染的光栅化阶段进行,用于获取纹理像素数据,有单一采样和多重采样两种。
采样数据属于离散型整数,在一些图片存在斜边或者旋转的时候,锯齿的出现就是因为采样计算导致。
在3D当中,多采用多重采样,在2D当中基本都是单一采样。 多重采样耗费性能很大。
如果需要抗锯齿的话,最简单的方式就是: 将图片进行缩小, 其本质就是纹理过滤。
图像格式
不同的图像格式采用的编码格式不同,他们主要的特点如下:
JPG/JPEG
采用的是有损压缩, 不支持Alpha通道, 这种压缩能够保证图片占用空间小,但有损质量。PNG
采用的是无损压缩,支持RGBA, 这种格式的图片质量很高GIF
采用的是无损压缩,多用于简单动画的使用BMP
无压缩,存储原始的图像数据,文件很大,不支持透明度, 是Windows系统标准图像文件格式。PSD
photoshop软件存储的格式,位图模式, 文件很大。
JPG
和PNG
是在项目开发中经常用到的两种格式,我们重点说明下:
JPG
采用有损压缩,不支持Alpha透明通道, 占用空间小,但图片质量稍差PNG
采用无损压缩,支持Alpha透明通道, 占用空间大,但图片质量好
在cocos2dx引擎中,所有图片的默认纹理格式为RGBA8888
,而JPG
的使用就会被强制转换为该纹理格式。
在cocosCreator的使用当中,这两种格式因为编译器的支持,很容易让人误会为纹理格式。
有些时候,因为各种原因需要程序对图片进行修改,推荐工具:
- Mac自带的图片预览工具,通过文件 --> 导出 支持PNG,JPEG等格式的转换及图片质量的选择。
- TinyPng 支持对图片的压缩,这个工具也被用来减少包体大小。
- 智慧工具库 支持将GIF压缩, 图片格式转换等
纹理格式
在项目运行中,CPU会将不同格式的图像转换为纹理,而纹理则被GPU在渲染流程的光栅化阶段通过采样获取数据进行着色渲染。
GPU是不支持对图像格式的解析的,它支持纹理格式类似于RGB
或RGBA
的解析。通过对不同通道设定对应的位数,而生成了不同的纹理格式。
常见的纹理格式有:
纹理格式 | 说明 | 用途 |
---|---|---|
RGBA8888 | 表示每个通道均占8bit,共32位 | 可用于高分辨率的显示 |
RGBA4444 | 表示每个通道均占4bit,共16位 | 可用于低分辨率的显示 |
RGB888 | 表示每个通道均占8bit,共24位 | 可用于不需要透明度的场景 |
RGB565 | 表示R占5bit,G占6bit,B占5bit,供16位 | 可用于需要透明度的场景或较小的内存占用 |
A8 | 表示A占8bit,共8位 | 可用于遮罩或透明度贴图 |
RGB5A1 | 表示RGB均占5bit, A占1bit, 共16位 | 可用于对透明度要求不太高的图像展示 |
不同通道的位数可以获取每个像素点的大小,进而获取图片的内寸占用:内存大小 = 宽 * 高 * bit/8
比如: 1024x1024的图片大小就是: 1024 * 1024 * 32/4 = 4194304byte, 大约为4M。
在cocos中谈及到纹理,就一定会有精灵帧。
精灵帧可借助TexturePacker工具或cocosCreator编译器的支持,都会生成精灵帧。
精灵帧主要用于将多张散图合并为一张大图,配置里面会包涵纹理的配置信息。就如上图工具里面可设置的纹理配置参数。
从性能优化角度来说:
- 推荐将同一模块的散图打包为图集, 减少DrawCall; 图集的大小不要超过2048*2048,否则会引起某些平台的崩溃
- cocos2dx推荐使用
SpriteFrameCache
和TextureCache
对纹理相关进行缓存, 并在合适的时机对无效缓存释放,注意先SpriteFrame, 再Texture; cocosCreator则是引用计数相关的处理和Bundle的释放 - 对图片要求质量不高或者分辨率低的设备可考虑使用
RGBA4444
格式
这里稍微拓展下,项目中的文本资源,大概有如下几种:
- 系统字体
- BMFont字体
- TTF字体
cocosCreator针对于文本做了CacheMode
的缓存支持,它支持将文本生成位图,用于减少DrawCall。其本质原因是文字内容绘制到屏幕当中的显示其实是纹理。
尤其针对于系统文字,它需要做一个纹理的转换,才能进行绘制, 而BMFont或TTF已经做了这些处理,故此比系统字体要快。
所以针对于cocosCreator的一些优化可以考虑:
- 针对于系统字体尽量使用合适的缓存模式
- 字体文件选择,尽量BMFont,不推荐占用包体太大的TTF字体,而且无效的TTF字可能也很多
- 字体的富文本使用,根据情况可推荐BMFont,因为描边和阴影效果会增加DrawCall次数
最后注意下:JPG和PNG这两种格式,从严格意义上来说,他们是图像而不是纹理,但某些资料也会将他们作为纹理来说明
压缩纹理
上面所说的一般作为常用的纹理, 而压缩纹理也属于纹理的一种,同样的也被GPU解析支持。
它是在1996年斯坦福大学发表的论文《基于已压缩纹理的渲染》提出,主要的思想是支持GPU从压缩包中获取数据。
这样做的目的是用来减少资源的大小,减少内存的占用。
通用的纹理,采用的压缩算法是基于整张纹理的,纹理像素之间存在着依赖关系,如果想获取某个像素数据需要其他的像素支持才行。
而压缩纹理会将纹理分为多个块,在获取某个纹理数据时,会先解压对应块,再根据索引偏移量获取获取纹理数据,这种被称为块(block-based)算法。
压缩纹理采用的是固定的压缩比率,他有如下的特点:
- 解压速度快,保证能够很快的获取数据,避免影响渲染性能,这是核心。
- 随机读取快,主要是为了纹理映射而方便快速的获取数据
- 编码慢,主要在于压缩纹理用于项目打包中使用,所以不太要求它的编码速度相关
- 内存占用小。
常用的压缩纹理格式主要有:
格式 | 支持 |
---|---|
ETC1 | 支持Android设备 |
ETC2 | 支持Android设备 |
PVRTC | 支持IOS设备 |
PVRTC1 | 支持IOS设备 |
ASTC | 支持部分Android和部分IOS设备 |
- ETC
它是爱立信公司在2005年提出, 支持4bpp压缩比率,采用的是有损压缩格式,仅保留了RGB通道。
在Android平台下压缩纹理一般会生成两张纹理表, 一张是RGB的纹理表,一张是对应的Alpha通道的纹理表, 在GPU中使用的时候会进行分别读取。
在后续的ETC2中,对ETC1进行了拓展,增加了对Alpha通道的支持, 硬件要求OpenGL ES3.0或OpenGL4.3以上
- PVRTC
它是由Imagination Technologies公司设计的, 被苹果平台使用, 主要有两种:PVRTC和PVRTC2。
他们都支持2bp和4bpp压缩比率, 都支持RGBA和RGB通道, 如果图像不支持Alpha通道会将其转换为RGB。
不过PVRTC仅支持POT纹理,也就是2的N次幂,而PVRTC2支持2的非N次幂。并且后者增强了PVRTC的图像质量,尤其针对于高对比度和大面积颜色不连续部分,或纹理的边沿。
- ASTC
它是由ARM和AMD联合开发的, 可根据不同图片选择不同压缩率算法, 大小不需要时2的幂次方,同时支持HDR和LDR。
其他
在cocos2dx中获取不同的纹理格式的支持,可参考:
// CCTexture2D.h
enum class PixelFormat {
AUTO, //! auto detect the type
BGRA8888, //! 32-bit texture: BGRA8888
RGBA8888, //! 32-bit texture: RGBA8888
RGB888, //! 24-bit texture: RGBA888
RGB565, //! 16-bit texture without Alpha channel
A8, //! 8-bit textures used as masks
I8, //! 8-bit intensity texture
AI88, //! 16-bit textures used as masks
RGBA4444, //! 16-bit textures: RGBA4444
RGB5A1, //! 16-bit textures: RGB5A1
PVRTC4, //! 4-bit PVRTC-compressed texture: PVRTC4
PVRTC4A, //! 4-bit PVRTC-compressed texture: PVRTC4 (has alpha channel)
PVRTC2, //! 2-bit PVRTC-compressed texture: PVRTC2
PVRTC2A, //! 2-bit PVRTC-compressed texture: PVRTC2 (has alpha channel)
ETC, //! ETC-compressed texture: ETC
S3TC_DXT1, //! S3TC-compressed texture: S3TC_Dxt1
S3TC_DXT3, //! S3TC-compressed texture: S3TC_Dxt3
S3TC_DXT5, //! S3TC-compressed texture: S3TC_Dxt5
ATC_RGB, //! ATITC-compressed texture: ATC_RGB
ATC_EXPLICIT_ALPHA, //! ATITC-compressed texture: ATC_EXPLICIT_ALPHA
ATC_INTERPOLATED_ALPHA, //! ATITC-compressed texture: ATC_INTERPOLATED_ALPHA
};
其中的S3TC相关,主要借助于DirectX而应用到window平台上。
感谢众多小伙伴的技术支持,参考资料:
cocosCreator 纹理贴图资源
cocosCreator 压缩纹理
Learn OpenGL 纹理
知乎 纹理压缩