Unity图片优化神器 - Dither算法进阶方案

news/2024/7/10 4:17:01 标签: unity, 优化, 算法, 色阶

原文链接:https://blog.uwa4d.com/archives/2001.html

这是侑虎科技第288篇原创文章,感谢作者喵小逗供稿,欢迎转发分享,未经作者授权请勿转载。当然,如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:465082844)

作者知乎专栏:https://zhuanlan.zhihu.com/p/28624490


在Unity移动平台的游戏开发过程中,贴图资源是往往是占资源量最大的资源。如何在保证视觉效果的同时,尽可能地减少贴图资源,是开发团队会经常遇到的问题。通常来说,对于3D物体的纹理,是可以采用ETC/PVRTC等压缩比很大的算法处理,但是对于细节要求很高的UI纹理,这样处理造成的失真往往达不到质量要求。对于这类的贴图,我们可以考虑使用失真较小的16位贴图格式存储。

但是对于颜色数较高的纹理,Unity提供的默认转换方法会呈现明显的色阶。针对该问题,keijiro实现了一种Dither4444的改进算法。从下图1上可以看到,对于画面细节比较平滑的图片,该算法虽然消除了色阶现象,同时带来了肉眼可见的噪点。

请输入图片描述
<图1> 左:原始图 右:keijiro的 Dither4444示意图

笔者在keijiro的算法基础上进行了改进,提供了一个将RGB24 Bit图Dither之后转RGB565的方法,基本消除了肉眼可见的失真,实际效果见下图2。

请输入图片描述
<图2> 左:原始图 右:笔者的 Dither565示意图

实际在我的项目的应用中,对于不适合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);
      }
}

文末,感谢喵小逗的分享,如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:465082844)。

也欢迎大家来积极参与U Sparkle开发者计划,简称"US",代表你和我,代表UWA和开发者在一起!



http://www.niftyadmin.cn/n/1031979.html

相关文章

【求知探新】《为谁而炼金》UI界面加载性能分析

原文链接&#xff1a;https://blog.uwa4d.com/archives/2006.html 【求知探新】是UWA新推出的栏目。在UWA团队做性能优化的过程中&#xff0c;常常会遇到一些未知的问题&#xff0c;在这里我们将分享UWA研究这些问题的完整过程。当然需要说明的是&#xff0c;一个好的问题没有标…

利用k8s部署Java项目

利用k8s部署Java项目 [rootk8s-master ~]# tree javaweb/ javaweb/ ├── Dockerfile └── files└── reduce-beta-1.0.jar制作镜像 [rootk8s-master ~]# cat javaweb/Dockerfile FROM openjdk:18-jdk-alpineCOPY files/reduce-beta-1.0.jar /usr/local/reduce-beta-1.…

布料系统原理浅析和在Unity手游中的应用

原文链接&#xff1a;https://blog.uwa4d.com/archives/2008.html 这是侑虎科技第291篇原创文章&#xff0c;感谢作者贾伟昊供稿&#xff0c;欢迎转发分享&#xff0c;未经作者授权请勿转载。当然&#xff0c;如果您有任何独到的见解或者发现也欢迎联系我们&#xff0c;一起探讨…

mysql 一张表有三个外键怎么写_MySql表,其中每一行对一个表有多个外键

我现在的情况是:表1包装清单:CREATE TABLE PackingList (PackingListId int(10) unsigned NOT NULL AUTO_INCREMENT,Sku char(10) NOT NULL DEFAULT ,PartId1 int(8) unsigned NOT NULL,PartId2 int(8) unsigned DEFAULT NULL,PartId3 int(8) unsigned DEFAULT NULL,PartId4 in…

Prometheus 容器化部署,配合Grafan画图工具监控节点

Prometheus、Grafan 容器化部署 环境说明 主机名IPmaster192.168.58.110client192.168.58.20 在master主机上安装docker docker安装 配置网络源&#xff08;rhel红帽系统&#xff09; [rootmaster ~]# curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.co…

UWA发布 | 2017 Unity手游体检蓝皮书 — MOBA篇

原文链接&#xff1a;https://blog.uwa4d.com/archives/2010.html 过去的一年&#xff0c;MOBA手游市场容量变得空前庞大&#xff0c;成了众多CP和发行追捧的对象&#xff0c;同时&#xff0c;其重社交、重玩法、重美术效果的高要求使得该品类游戏也面临着前所未有的性能挑战&a…

FPS手游《战地先锋》性能案例精讲

原文链接&#xff1a;https://blog.uwa4d.com/archives/2012.html 今天我们为大家带来由上海非钰数码科技的FPS手游《战地先锋》的 UWA测评报告分析。该游戏在各种档次的移动终端设备上&#xff0c;无论是画面表现力&#xff0c;还是性能开销都非常优异。在此&#xff0c;我们将…

mysql atlas导出数据_msyql的备份和复制和atlas 的区别

备份&#xff1a;mysqldump &#xff1a;将数据从数据库中导出再进行导入&#xff0c;数据完全一样&#xff0c;但有时效性&#xff0c;数据量大时备份会是个麻烦事。主从复制&#xff1a;mysql replication &#xff1a;有备份mysql的效果。将主mysql上执行的命令&#xff0c;…