Notifications
Article
说说Unity纹理压缩技术与策略(一)
Updated 12 days ago
1.1 K
0
最近在Connect社区上看到有许多同学在问纹理压缩方面的问题,想着跟大家聊聊Unity纹理压缩技术方面的内容,也希望大家在社区多交流,共同进步~
游戏制作过程中的主要矛盾是开发者日益增长的表现追求与设备资源的限制之间矛盾,且矛盾不会随设备的发展而转移, 纹理压缩技术就是矛盾的一种解决方式。------------------鲁迅
我们从纹理优化入手,避免后期优化中出现的坑,所以项目制作前,了解Unity包体和内存对图片的需求很有必要,希望通过这一系列文章讲下Unity的纹理压缩技术的一些内容。在开始之前先解释几个概念,图片显示到屏幕CPU与GPU如何工作的与什么是纹理格式、文件格式以及压缩纹理格式?
图片显示到屏幕上是CPU与GPU的协作完成的过程。其中CPU: 计算视图frame,图片解码,需要绘制纹理图片通过数据总线交给GPU。GPU: 纹理混合,顶点变换与计算,像素点的填充计算,渲染到帧缓冲区。
其实整个过程远比这个复杂(如上图),我们现在只关注CPU对图片解码之后.交给GPU采样这个过程。不同于PNG、JGP这种硬盘压缩方式的文件格式 ,DXT,ETC等压缩纹理格式可以在游戏运行中无需CPU解压就被GPU直接采样,图片的解码是一个复杂耗时的过程,并且需要占用比原始图片更多的内存资源,所以压缩纹理格式可以极大的减少内存和带宽的占用,提升运行效率,对移动端游戏而言这点更为重要。
敲到麻袋!什么是纹理格式、文件格式以及压缩纹理格式呢?
1.纹理格式
这种格式是图片原生的纹理,图片有多大它就是多大且能够被GPU直接处理过的 常见的纹理格式是:R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8, A8R8G8B8
2.文件格式
我们说的JPG,PNG指的是文件格式,就是图片在硬盘里面存储的格式,或者是手机的存储里面的格式,游戏的资源的格式。所有储存在硬盘中的JPG,PNG等图片,其实都是跟ZIP,RAR一样压缩包的东西。 而JPG,PNG也是图片特有的压缩包,是为了便于传输和缩小占用压缩空间所诞生的图片特有的压缩方法 但是这种JPG,PNG等压缩算法是不能够被GPU识别的,必须得解压缩以后才能够被GPU识别(解压缩后就是纹理格式了)这也就解释了Connect社区里小伙伴提出的问题为什么一些PNG图片,在硬盘中占用几KB,怎么在Unity中显示却变大?因为Unity显示的是Texture大小,是实际运行时占用内存的大小,而PNG却是一种压缩显示的文件格式。
3.压缩纹理格式
这个听起来比较拗口,因为已经有压缩格式和纹理格式了,为什么还要增加一个压缩纹理格式。首先文件格式是不能够被GPU直接识别的,在渲染前都得先要解压缩成纹理格式后才能够被GPU识别,在移动平台上的游戏解压缩时间太长了,而且每个游戏都会大量使用图片,所以在移动平台上使用压缩格式的图片是不被接受的。其次纹理格式中 R5G6B5,A4R4G4B4,A1R5G5B5每个像素占用2个字节,R8G8B8每个像素占用3个字节,A8R8G8B8每个像素占用 4个字节。也就是说对于一张512*512的纹理的话,R5G6B5格式的文件需要占用512KB的容量,A8R8G8B8格式的文件需要占用1MB的容量;如果是 1024*1024的纹理,则各需要2M和4M的容量。
这对于动辄需要几十、几百张甚至更多纹理的游戏,上G容量的游戏在移动平台上是不被接受的。那么有没有其他办法,既能表现丰富的色彩和细节,又能是最小失真的情况下,达到更小的纹理容量呢,还能够GPU识别和读取的纹理。这就是压缩纹理格式。
铛铛铛,我们简单的总结下纹理压缩技术的优点:解决了内存和显存(GPU的专用内存)中纹理占用空间大的问题,不需要在CPU中就解压缩,在GPU中也不需要对整个图片解压缩;解决了带宽问题,从CPU传到GPU的图片是压缩格式,因此传输的数据量会小很多,大大减轻了带宽压力;解决了包体大小的问题,打包到游戏内的纹理是直接处理好的压缩格式。
接着我们来说下Unity纹理压缩技术。默认情况下,Unity会自动将纹理转换为最合适的格式,来匹配你选择的构建目标。构建中仅包含转换后的纹理;您的源资产文件将以其原始格式保留在项目的“资产”文件夹中。但是,在大多数平台上,有多种支持的纹理压缩格式可供选择。 Unity为每个平台设置了某些默认格式,但是在某些情况下,您可能需要覆盖默认格式,并为某些纹理选择不同的压缩格式(例如,如果您使用纹理作为MASK,则仅使用一个通道,则可以选择使用BC4格式来节省空间,同时又保持质量,但是在实际的开发过程中这种情况几乎可以忽略不计)。
Unity对纹理的处理是智能的:不论你放入的是PNG,PSD还是TGA,它们都会被自动转换成Unity自己的Texture2D格式。在Texture2D的设置选项中,你可以针对不同的平台,设置不同的压缩格式,如IOS设置成PVRTC4等,Android平台设置成RGBA16等。
Unity支持的压缩格式的分类: PC、MAC、Linux、Android平台和IOS平台分别如下图所示;
我们这里主要讨论Android和IOS两大移动平台;目前移动市场的GPU主要有四大厂商(不吹不黑,其实主要是三家)
接着我们介绍下常见的几种纹理压缩格式:
ETC纹理压缩格式
ETC  -- 安卓原生支持的,OPNEGL2.0都支持,Ericsson Texture Compression,是由 Khronos 支持的开放标准,在移动平台中广泛采用。它是一种为感知质量设计的有损算法,其依据是人眼对亮度改变的反应要高于色度改变。类似于DXT,ETC也是把4x4的像素块压缩成一个64或128位的数据块,也是有损压缩。
ETC1把一个4x4的像素单元组压成一个64位的数据块。4x4的像素组先被水平或垂直分割成2个4x2的组,每一半组有1个基础颜色(分别是RGB444/RGB444或RGB555/RGB333格式)、1个4位的亮度索引、8个2位像素索引。每个像素的颜色等于基础颜色加上索引指向的亮度范围。
ETC2 -- ETC2是ETC1的扩张,向后兼容ETC1,对RGB的压缩质量更好,并且支持透明通道。目前下列ETC2压缩格式在OpenGL ES 3.0和OpenGL 4.3上被要求支持:
GL_COMPRESSED_RGB8_ETC2 压缩的RGB888格式,类似于ETC1
GL_COMPRESSED_RGBA8_ETC2_EAC 压缩的RGBA8888格式,支持完全的透明通道
GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 压缩的RGBA数据,只有一位Alpha
ETC2比ETC1压缩质量更高,而且支持透明,在Android设备上再也不需要打不同纹理格式的包了。不过需要OpenGL ES 3.0以上才可以,目前很多设备只支持OpenGL ES 2.0。
PVRTC纹理压缩格式
PVRTC -- Imagination PowerVR提供PowerVR Texture Compression,PVRTC格式与基于块的压缩格式,比如S3TC、ETC的不同之处是,它使用2张双线性放大的低分辨率图,根据精度和每个像素的权重,融合到一起来呈现纹理,并且2-bpp和4-bpp都支持ARGB数据。PVRTC格式压缩比高,也是有损压缩
ASTC纹理压缩格式
ASTC -- 从IOS9(A8架构)Apple 手机开始支持ASTC压缩格式 ,如果考虑放弃Apple 6代之前的手机兼容问题了,可以直接使用了。相对于PVRTC2/4而言,ASTC(4X4)的压缩比会增加到0.25,不过显示效果也会好很多,而且不需要把图片设置为方形。
Unity已经很智能,但是在实际的开发过程中我们会遇到各种各样的情况。比如,我们NGUI的图集纹理,在Android平台,使用ETC1纹理+Alpha通道图的方式;iOS平台,使用PVRTC4的纹理。个别图片纹理,要求清晰度较高的,使用RGBA16,但是使用RGBA16的渐变显示图片效果不理想;一些要求高保真的,则需要直接使用最高质量的RGBA32格式。很多时候,随着项目的复杂需求发展,单纯的Unity纹理管理已经无法满足我们的需求了。这时候,往往需要我们做一些额外工作。
这些内容我会在后期的文章中给大家分享。
梦想在路上的LPP
来自古城西安的浪漫主义Unity爱好者 - Programmer
8
Comments
Comment disabled