• cocos 之纹理格式和压缩纹理


    Cocos2dx 版本: 3.10

    CocosCreator 版本: 3.8.0

    环境: Mac


    简介


    项目开发中,图片资源的优化是作为性能优化和包体优化的一项重要策略。常用的手段有:

    • 使用TexturePacker将散图打包图集;选择合适的纹理格式
    • JPGPNG的使用,从包体来说JPG更小,从性能来说PNG更快
    • 使用压缩纹理对游戏进行打包,Android的ETC,IOS的PVRTC

    在这里面已经涉及到对纹理的理解,比如来说:

    • 关于TexturePacker工具里面的参数设定

    请添加图片描述

    注: RGBA4444比RGBA8888要省掉一半的内存, NPOT要比POT的大小要小一些

    • 关于cocos2dx引擎对纹理Texture2D的封装使用
    • 关于cocosCreator对ImageAsset资源下的Texture的参数设定
    • 关于使用OpenGL ES 渲染中锯齿的出现原因

    这些都跟 纹理 挂钩, 了解纹理有助于我们做更好的游戏。

    对我而言,纹理是一个让人很惧怕的词汇。

    在刚入行的时候我不知道它到底代表着什么,入行cocos2dx以后,了解到渲染,了解到OpenGL ES, 我才对纹理有所了解。 再遇到现在的cocosCreator 。

    理解可能有所误解,希望看到的小伙伴能进行反馈,共同学习和成长, 感谢!


    基础概念


    在开始之前,以cocos2dx为例,简要说明下渲染的流程, 这对于后面的理解纹理格式是有帮助的。

    如果有小伙伴想详细的了解cocos2dx的渲染流程,可参考我之前写的博客:

    cocos2d-x 渲染机制简介

    cocos2d-x 绘制命令

    cocos2d-x OpenGL ES 简介

    图片是效果展示的最直接表现,而纹理是渲染效果实现的重要基础。

    我们会将JPGPNG的不同图像格式的资源放置在项目中,引擎会针对于不同的图像格式通过CPU转换为RGB或者RGBA纹理格式。简单的理解:

    • 不同图像格式,比如JPGPNG,是被我们所使用并放在CPU中的
    • 图像所生成的效果是由CPU将不同的图像格式转换为纹理格式通过GPU所渲染的。

    注: GPU是不能识别图像格式的资源的,必须转换才能使用。

    纹理格式被GPU用来读取获取纹理数据,并借助于OpenGL ES对纹理数据进行采样,将采样数据交给片段着色器着色,从而完成渲染的目的。


    这里需要我们注意几个概念:

    1. 图像

    指的是JPG,PNG,GIF,JPEG等图片资源,采用特殊编码生成的存储格式,用于传输和存储图像信息。

    1. 纹理

    分为未压缩纹理压缩纹理两类,它主要被OpenGL用来采样获取纹理数据进行渲染

    1. 纹理像素

    JPG为例,在图片放大以后发现由多个像素点组成,这个像素点就叫做纹理像素, 也被称为纹素。

    每个像素点由RGBRGBA组成,不同的像素数值组成一幅彩色的图像。

    1. 采样

    在OpenGL渲染的光栅化阶段进行,用于获取纹理像素数据,有单一采样和多重采样两种。

    采样数据属于离散型整数,在一些图片存在斜边或者旋转的时候,锯齿的出现就是因为采样计算导致。

    在3D当中,多采用多重采样,在2D当中基本都是单一采样。 多重采样耗费性能很大。

    如果需要抗锯齿的话,最简单的方式就是: 将图片进行缩小, 其本质就是纹理过滤


    图像格式


    不同的图像格式采用的编码格式不同,他们主要的特点:

    • JPG/JPEG 采用的是有损压缩, 不支持Alpha通道, 这种压缩能够保证图片占用空间小,但有损质量。
    • PNG 采用的是无损压缩,支持RGBA, 这种格式的图片质量很高
    • GIF 采用的是无损压缩,多用于简单动画的使用
    • BMP 无压缩,存储原始的图像数据,文件很大,不支持透明度, 是Windows系统标准图像文件格式。
    • PSD photoshop软件存储的格式,位图模式, 文件很大。

    注:JPGPNG是在项目开发中经常用到的两种图像格式,在某些资料中,他们也会被作为纹理来说明

    在cocos2dx引擎中,所有图片的默认纹理格式为RGBA8888,而JPG的使用就会被强制转换为该纹理格式。

    在cocosCreator的使用当中,这两种格式因为编译器的支持,很容易让人误会为纹理格式。


    有些时候,包体压缩 需要对图片进行修改,推荐工具:

    • Mac自带的图片预览工具,通过文件 --> 导出 支持PNG,JPEG等格式的转换及图片质量的选择。
    • TinyPng 支持对图片的压缩,这个工具也被用来减少包体大小。
    • 智慧工具库 支持将GIF压缩, 图片格式转换等

    注: 图片格式的转换,简单的来说以性能换空间


    纹理格式


    在项目运行中,CPU会将不同格式的图像转换为纹理,纹理则被GPU通过采样获取纹理数据进行渲染。

    GPU是不支持对图像格式的解析的,它支持纹理格式类似于RGBRGBA的解析。

    通过对不同通道设定对应的位数,而生成了不同的纹理格式。常见的纹理格式有:

    纹理格式说明用途
    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。
    * 使用不同的纹理格式可以优化内存的占用
    * RGBA4444 比 RGBA8888 的内存占用小一半左右, 这个就是纹理格式有多种的原因。
    * 在性能优化过程中, 使用TexturePacker是一个很好的性能优化的工具。
    
    • 1
    • 2
    • 3
    • 4

    注: 不同的纹理格式有着不同的使用场景,单纯的从包体优化来考虑,对图片的显示质量没有太高的要求,那就RGBA4444


    精灵帧

    谈及到纹理,就一定会有精灵帧。它可借助外部工具 TexturePacker 或cocosCreator编译器的自动图集生成。

    简单的理解:它将多张散图合并为一张大图,配置里面会包涵纹理的配置信息,相当于是纹理的一个集合数据。

    性能优化角度来说:

    • 推荐将同一模块的散图打包为图集, 减少DrawCall的请求次数;
    • 图集的大小不要超过2048*2048,否则会引起某些平台的崩溃
    • cocos2dx使用SpriteFrameCacheTextureCache对纹理相关进行缓存, 并在合适的时机对无效缓存释放
    • 注意先SpriteFrame, 再Texture; cocosCreator则是引用计数相关的处理和Bundle的释放
    • 对图片要求质量不高或者分辨率低的设备可考虑使用RGBA4444格式
    • JPGPNG的合理使用

    字体

    字体资源也是渲染效果展示的一种重要方式,主要资源有:系统字体、BMFont字体(图片字)、TTF字体

    • 系统字体 使用最方便,但性能最低
    • BMFont字体 图片字,使用灵活,可以实现更渲染的效果,但资源不太好维护
    • TTF字体 使用灵活,但占用内存最高,资源很大

    注: 系统字在渲染中会被强制转换为纹理,才能被绘制;而BMFont和TTF则没有该步骤,故此性能比系统字要高。

    在cocosCreator中,针对于系统字增加了CacheMode的缓存支持,它支持将文本生成位图,用于减少DrawCall。

    从性能优化和包体优化角度来说:

    • 系统字体尽量使用合适的缓存模式
    • 字体文件选择,尽量BMFont,不推荐占用包体太大的TTF字体,而且无效的TTF字可能也很多
    • 字体的富文本使用,根据情况可推荐BMFont,因为描边和阴影效果会增加DrawCall次数

    注:系统字体占用包体小,但是渲染耗性能; TTF性能高,但是占用包体大; 所以最合适的资源是BMFont


    压缩纹理


    上面所说的一般纹理格式,通常作为常用的纹理。

    压缩纹理也属于纹理的一种,同样的也被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以上

    注: 包体优化,可对RGB纹理表使用RGBA8888格式, Alpha表使用RGBA4444格式; 这种方式除非逼不得已再使用吧。倒是可以作为一种思路推荐。


    • PVRTC

    它是由Imagination Technologies公司设计的, 被苹果平台使用, 主要有两种:PVRTCPVRTC2

    他们都支持2bp和4bpp压缩比率, 都支持RGBA和RGB通道, 如果图像不支持Alpha通道会将其转换为RGB。

    不过PVRTC仅支持POT纹理,也就是2的N次幂,而PVRTC2支持2的非N次幂。并且后者增强了PVRTC的图像质量,尤其针对于高对比度和大面积颜色不连续部分,或纹理的边沿。

    注: 在TexturePacker工具上有这个POT和NPOT的选择。


    • 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
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    其中的S3TC相关,主要借助于DirectX而应用到window平台上。


    结语


    纹理的使用主要的目的:

    • 性能优化
    • 包体优化

    了解纹理格式,有助于对引擎的渲染进行了解, 以及提升项目的健全性。

    在项目开发中,可以做如下几方面的考虑:

    • 某些较大的图片是否需要将PNG替换为JPG格式
    • 某些图片资源是否需要程序使用TinyPng进行压图
    • 某些字体资源是否需要进行优化, 选择系统字体还是BMFont
    • 散图和图集的合理选择,不是所有的资源都需要图集的
    • 使用TexturePacker中,是否需要设置下纹理格式, 尤其针对于低分辨率的设置
    • Android平台下的ETC1纹理打包, 如果考虑到极致,可以使用纹理压缩工具可以将RGB图和Alpha图再进行压缩优化

    废话了这么多,其实我很怀念当初的小霸王游戏机中的魂斗罗和冒险岛游戏, 平均大小187KB
    虽能力有限,无法达到当年程序大神的高度,但努力总会值得。

    最后,感谢众多小伙伴的技术支持,参考资料:

    cocosCreator 纹理贴图资源
    cocosCreator 压缩纹理
    Learn OpenGL 纹理
    知乎 纹理压缩

    祝大家学习生活愉快!


  • 相关阅读:
    第三阶段学习beiqi3
    Qt实现自定义控件的两种方式之提升法
    捷报 | 美格智能Cat.1模组SLM332中标中国电信定制版Cat.1模组产品招募
    vue3.0+vite+ts项目搭建报错问题的处理
    四川水泥杂志四川水泥杂志社四川水泥编辑部2022年第11期目录
    Nginx内存池(内存池重置函数)
    植物大战僵尸各种僵尸攻略
    shell变量
    面试:插件化相关---资源
    施耐德电气携中国信通院和中国联通共同发布白皮书,共探5G+PLC深度融合应用
  • 原文地址:https://blog.csdn.net/qq_24726043/article/details/132743453