参考链接(总结还是比较全):https://blog.csdn.net/goodai007/article/details/52679333
参考链接:https://zhuanlan.zhihu.com/p/28624490
后续有新思路 持续更新
总结一下 查看的时候方便 也防止原链接失效(如有需求 请去原链接支持)
文章包括:
1.纹理压缩策略
2.图片优化神器 - Dither算法进阶方案(附代码)
3.图片alpha分离(TODO 待整理)
**
纹理压缩策略
**
Unity3D引擎对纹理的处理是智能的:不论你放入的是PNG,PSD还是TGA,它们都会被自动转换成Unity自己的Texture2D格式。
在Texture2D的设置选项中,你可以针对不同的平台,设置不同的压缩格式,
如IOS设置成PVRTC4
Android平台设置成RGBA16等
手游开发(Android/IOS)中,我会使用3个级别的压缩程度:高清晰无压缩、中清晰中压缩、低清晰高压缩;4种压缩方法:RGBA32, RGBA16+Dithering,ETC1+Alpha,PVRTC4。一般足够应付大部分的需求了。
-
高清晰无压缩 - RGBA32
Unity RGBA32 - 高清晰无压缩.png
RGBA32等同于原图了,优点是清晰、与原图一致,缺点是内存占用十分大;对于一些美术要求最好清晰度的图片,是首选。
要注意一些png图片,在硬盘中占用几KB,怎么在Unity中显示却变大?因为Unity显示的是Texture大小,是实际运行时占用内存的大小,而png却是一种压缩显示格式;可以这样理解,png类似于zip格式,是一个压缩文件,只不过在运行时会自动解压解析罢了。
-
中清晰中压缩 - RGBA16 + Dithering
Unity RGBA16,不抖动处理的渐变图片惨不忍睹
既然叫RGBA16,自然就是RGBA32的阉割版。
对于一些采用渐变的图片,从RGBA32转换成RGBA16,能明显的看出颜色的层叠变化
采用Floyd Steinberg抖动处理后,除非放大,否则肉眼基本看不出区别
RGBA16的优点: 内存占用是RGBA32的1/2;搭配上Dithering抖动,在原尺寸下看清晰度一模一样;
缺点: Unity原生不支持Dithering抖动,需要自己做工具对图片做处理;对于需要放大、拉伸的图片,Dithering抖动的支持不好,会有非常明显的颗粒感。
如何进行Dithering抖动?
Texture Packer工具中Image Format选择RGBA4444,Dithering选择FloydSteinberg
在我的项目中,TexturePacker具有非常重要的作用,像UI的图集生成,预先生成好正方形的IOS PVRTC4图集和非正方形的Android ETC1图集、 缩放原图50%等工作都由TexturePacker完成。
同样,对图像进行抖动处理,也是预先在TexturePacker使用FloydSteinberg算法进行图像抖动,再在Unity中导入使用。
TexturePacker提供命令行工具,可以做成自动化的工具。
-
RGB16
RGB16,是主要针对一些,不带透明通道,同时长宽又不是2的次方的图片;对于这些图片,使用RGB16可以降低一半的内存,但是效果会略逊于RGB32。
当然了,RGB16其实也是可以搭配抖动,也能提升显示效果;但同样的Dithering抖动对拉伸放大是不友好的。
-
低清晰高压缩 - ETC1+Alpha/PVRTC4
很多初学者都会疑惑,为什么游戏开发中经常看到一些图片,需要设置成2的次方?因为像ETC1、PVRTC4等这类在内存中无需解压、直接被GPU支持的格式,占用内存极低,而且性能效率也是最好的。
但是,相对RGBA32,还是能肉眼看出质量有所下降的。
-
ETC1
ETC1+Alpha一般应用在Android版的UI图集中,ETC1不带透明通道,所以需要外挂一张同样是ETC1格式的Alpha通道图。方法是,在原RGBA32的原图中,提取RGB生成第一张ETC1,再提取A通道,填充另一张ETC1的R通道;游戏运行时,Shader将两张ETC1图片进行混合。
要配合ETC1+Alpha,还需要Shader支持,这里提供参考直接修改NGUI的Unlit/Transparent With Colored的Shader。
生成Alpha通道图的方法可参考(后续整理到帖子):http://blog.csdn.net/u010153703/article/details/45502895
-
PVRTC4
PVRTC4在Unity中是直接支持的,不过要注意的细节是,它必须是二次方正方形;也就是说,长宽在二次方的同时,还必须要相等。
-
几种纹理格式的对比
原作者感受:
在项目中,尽可能是使用ETC1和PVRTV4等GPU直接支持的图片格式,不仅内存占用低、性能也更好;当出现质量不及格时,再逐步的提升压缩格式,来满足需要。
因此,实际项目中要混搭各种纹理格式。
**
Dither算法进阶方案
**
在Unity移动平台的游戏开发过程中,贴图资源是往往是占资源量最大的资源。如何在保证视觉效果的同时,尽可能的减少贴图资源,是开发团队会经常遇到的问题。通常来说,对于3D物体的纹理,是可以采用ETC/PVRTC等压缩比很大的算法处理的,但是对于细节要求很高的UI纹理,这样处理造成的失真往往达不到质量要求。对于这类的贴图,我们可以考虑使用失真较小的16位的贴图格式存储。
但是对于颜色数较高的纹理,Unity提供的默认转换方法会呈现明显的色带。针对该问题,keijiro实现了一种dither4444的改进算法。从图1上可以看到,对于画面细节比较平滑的图片,该算法虽然消除了色带现象,同时带来了肉眼可见的噪点。
笔者在keijiro的算法基础上进行了改进,提供了一个将RGB24bit图dither之后转RGB565的方法,基本消除了肉眼可见的失真
实际在项目的应用中,对于不适合ETC/PVRTC压缩的图片,都采用了该文章中的RGB565或者RGB565+A8的方式。在肉眼基本无失真的基础上,节省了部分资源。
附上OnPostprocessTexture代码(感谢原作者):
void OnPostprocessTexture (Texture2D texture)
{
if(assetPath.Contains ("_dither565"))
{
var texw = texture.width;
var texh = texture.height;
var pixels = texture.GetPixels ();
var offs = 0;
var k1Per31 = 1.0f / 31.0f;
var k1Per32 = 1.0f / 32.0f;
var k5Per32 = 5.0f / 32.0f;
var k11Per32 = 11.0f / 32.0f;
var k15Per32 = 15.0f / 32.0f;
var k1Per63 = 1.0f / 63.0f;
var k3Per64 = 3.0f / 64.0f;
var k11Per64 = 11.0f / 64.0f;
var k21Per64 = 21.0f / 64.0f;
var k29Per64 = 29.0f / 64.0f;
var k_r = 32; //R&B压缩到5位,所以取2的5次方
var k_g = 64; //G压缩到6位,所以取2的6次方
for(var y = 0; y < texh; y++){
for(var x = 0; x < texw; x++){
float r = pixels [offs].r;
float g = pixels [offs].g;
float b = pixels [offs].b;
var r2 = Mathf.Clamp01 (Mathf.Floor (r * k_r) * k1Per31);
var g2 = Mathf.Clamp01 (Mathf.Floor (g * k_g) * k1Per63);
var b2 = Mathf.Clamp01 (Mathf.Floor (b * k_r) * k1Per31);
var re = r - r2;
var ge = g - g2;
var be = b - b2;
var n1 = offs + 1;
var n2 = offs + texw - 1;
var n3 = offs + texw;
var n4 = offs + texw + 1;
if(x < texw - 1){
pixels [n1].r += re * k15Per32;
pixels [n1].g += ge * k29Per64;
pixels [n1].b += be * k15Per32;
}
if(y < texh - 1){
pixels [n3].r += re * k11Per32;
pixels [n3].g += ge * k21Per64;
pixels [n3].b += be * k11Per32;
if(x > 0){
pixels [n2].r += re * k5Per32;
pixels [n2].g += ge * k11Per64;
pixels [n2].b += be * k5Per32;
}
if(x < texw - 1){
pixels [n4].r += re * k1Per32;
pixels [n4].g += ge * k3Per64;
pixels [n4].b += be * k1Per32;
}
}
pixels [offs].r = r2;
pixels [offs].g = g2;
pixels [offs].b = b2;
offs++;
}
}
texture.SetPixels (pixels);
EditorUtility.CompressTexture (texture, TextureFormat.RGB565, TextureCompressionQuality.Best);
}
}
来源:https://blog.csdn.net/qq_45504161/article/details/99107451