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

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

https://blog.uwa4d.com/archives/2001.html

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

  • 作者:admin
  • /
  • 时间:2017年08月22日
  • /
  • 浏览:11555 次
  • /
  • 分类:厚积薄发

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

作者知乎专栏: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);
      }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Unity SGP4-SDP4算法是一种用于计算卫星轨道位置和速度的算法。它是基于SGP4(Simplified General Perturbations 4)和SDP4(Simplified Deep-Space Perturbations 4)两种算法的结合。 SGP4算法是一种用于计算近地轨道卫星的位置和速度的简化模型。它使用了牛顿万有引力定律和扰动项来考虑地球引力、太阳引力、月球引力等因素对卫星轨道的影响。SGP4算法采用了一系列数学公式和常数,通过迭代计算,可以得出卫星在地球上的位置和速度。 SDP4算法是一种用于计算深空卫星的位置和速度的简化模型。由于深空卫星的轨道比较复杂,所以SDP4算法引入了更多的扰动项来考虑更多的因素,如地球的非球形引力、太阳风等。SDP4算法同样利用数学公式和常数,通过迭代计算,可以得出卫星在太阳系中的位置和速度。 Unity SGP4-SDP4算法结合了SGP4算法和SDP4算法的优点,既可以计算近地轨道卫星的位置和速度,也可以计算深空卫星的位置和速度。它能够准确地模拟卫星在不同时刻的轨道轨迹,并可以在Unity引擎中应用于卫星轨道仿真、导航系统等领域。 总的来说,Unity SGP4-SDP4算法是一种用于计算卫星轨道位置和速度的综合算法,具有较高的精度和可靠性,可以应用于多种领域中的卫星轨道仿真和导航系统。 ### 回答2: Unity SGP4-SDP4算法是一种用于预测地球上卫星轨道的科学计算方法。SGP4代表了"简化通用轨道预测模型4",而SDP4代表了"统计模型4"。这两个模型是用来预测不同高度和倾角的低地轨道卫星的轨道。 SGP4-SDP4算法基于开普勒定律和地球引力模型行计算。它的输入参数包括了卫星的初始轨道元素(如半长轴、偏心率、倾角等),并考虑了地球引力、大气阻力和其他外力的影响。 SGP4模型主要用于计算低地轨道卫星的轨道,它的预测结果在大约一周内的时间范围内是非常准确的。而SDP4模型则用于计算更高倾角和更高高度的轨道,它在大约一年内的时间范围内提供准确的预测。 Unity SGP4-SDP4算法在地球科学研究、航天工程和卫星导航等领域具有重要的应用。它可以用来计算和预测卫星的位置、速度和轨道等信息,从而为卫星定位、通信和导航系统提供支持。 总之,Unity SGP4-SDP4算法是一种用于预测地球上卫星轨道的计算方法,它基于开普勒定律和地球引力模型,结合了SGP4和SDP4两种模型,能够在不同时间范围内准确预测卫星的轨道信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值