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

简介:

在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);
      }
}






原文出处:侑虎科技
本文作者:admin
转载请与作者联系,同时请务必标明文章原始出处和原文链接及本声明。

目录
相关文章
|
1月前
|
算法
经典控制算法——PID算法原理分析及优化
这篇文章介绍了PID控制算法,这是一种广泛应用的控制策略,具有简单、鲁棒性强的特点。PID通过比例、积分和微分三个部分调整控制量,以减少系统误差。文章提到了在大学智能汽车竞赛中的应用,并详细解释了PID的基本原理和数学表达式。接着,讨论了数字PID的实现,包括位置式、增量式和步进式,以及它们各自的优缺点。最后,文章介绍了PID的优化方法,如积分饱和处理和微分项优化,以及串级PID在电机控制中的应用。整个内容旨在帮助读者理解PID控制的原理和实际运用。
87 1
|
6天前
|
机器学习/深度学习 算法 前端开发
Scikit-learn进阶:探索集成学习算法
【4月更文挑战第17天】本文介绍了Scikit-learn中的集成学习算法,包括Bagging(如RandomForest)、Boosting(AdaBoost、GradientBoosting)和Stacking。通过结合多个学习器,集成学习能提高模型性能,减少偏差和方差。文中展示了如何使用Scikit-learn实现这些算法,并提供示例代码,帮助读者理解和应用集成学习提升模型预测准确性。
|
8天前
|
算法
R语言使用随机技术差分进化算法优化的Nelson-Siegel-Svensson模型
R语言使用随机技术差分进化算法优化的Nelson-Siegel-Svensson模型
15 0
|
11天前
|
算法 定位技术 图形学
unity3d寻路算法
unity3d寻路算法
|
15天前
|
算法 数据处理 C语言
【数据结构与算法】快速排序(详解:快排的Hoare原版,挖坑法和双指针法|避免快排最坏时间复杂度的两种解决方案|小区间优化|非递归的快排)
【数据结构与算法】快速排序(详解:快排的Hoare原版,挖坑法和双指针法|避免快排最坏时间复杂度的两种解决方案|小区间优化|非递归的快排)
|
16天前
|
算法 索引
【算法与数据结构】深入二叉树实现超详解(全源码优化)
【算法与数据结构】深入二叉树实现超详解(全源码优化)
|
29天前
|
机器学习/深度学习 算法 大数据
基于PyTorch对凸函数采用SGD算法优化实例(附源码)
基于PyTorch对凸函数采用SGD算法优化实例(附源码)
29 3
|
1月前
|
算法 搜索推荐 测试技术
python排序算法及优化学习笔记1
python实现的简单的排序算法,以及算法优化,学习笔记1
33 1
|
1月前
|
算法 搜索推荐
基于遗传优化的协同过滤推荐算法matlab仿真
该内容是关于推荐系统和算法的描述。使用Matlab2022a执行的算法生成了推荐商品ID列表,显示了协同过滤在个性化推荐中的应用。用户兴趣模型通过获取用户信息并建立数学模型来提高推荐性能。程序片段展示了遗传算法(GA)的迭代过程,确定支持度阈值,并基于关联规则生成推荐商品ID。最终结果是推荐的商品ID列表,显示了算法的收敛和支持值。
|
1月前
|
算法
PID算法原理分析及优化
这篇文章介绍了PID控制方法,一种广泛应用于机电、冶金等行业的经典控制算法。PID通过比例、积分、微分三个部分调整控制量,以适应系统偏差。文章讨论了比例调节对系统响应的直接影响,积分调节如何消除稳态误差,以及微分调节如何减少超调。还提到了数字PID的实现,包括位置式、增量式和步进式,并探讨了积分饱和和微分项的优化策略。最后,文章简述了串级PID在电机控制中的应用,并强调了PID控制的灵活性和实用性。
39 1