zoukankan      html  css  js  c++  java
  • Unity RGBA16 + Dither

    游戏开发中有些场合,ETC或者说PVRTC压缩质量不满足的情况下,RGBA32(原图)对美术而言肯定可以满足的,但是RGBA32是不管是对内存占用内存太厉害. RGBA16/RGB16会减少内存的占用,但是Unity中并没有处理色阶的问题,看起来会使这样:
    mark|center|
    之前有文章提到过使用对图片预先进行Dither(抖动)处理之后,再使用RGBA16压缩,就会消除或者说减少色阶问题,不过作者使用的是TexturePacker进行的处理,而对于不采用TexturePacker进行UI Atlas打包的Unity项目就要换种思路实现。

    Image Dither

    图像抖动的基本原理是误差扩散,也就是将减少色阶后的误差扩散到周边像素,减少相邻像素点整体的误差,从而使肉眼在观察图片时没有那么明显的色阶问题,如下图:
    mark

    更多详细描述可以阅读:http://www.tannerhelland.com/4660/dithering-eleven-algorithms-source-code/,里面对几种dither算法了详细描述,并给出了处理后的效果。具体的实现可以参考github:
    https://github.com/minhhh/unity-texture-dither。对比了几种效果,我最后采用Floyd–Steinberg抖动算法。

    Unity 图片预处理

    具体实现中,可以在Unity导入图片时通过unity AssetPostprocessor对需要进行压缩的图片进行Dither处理,具体代码:

    using UnityEngine;
    using UnityEditor;
    using System.Collections;
    
    class TextureModifier : AssetPostprocessor
    {
        void OnPreprocessTexture()
        {
            var importer = (assetImporter as TextureImporter);
    
            importer.textureType = TextureImporterType.GUI;
    
            if (assetPath.EndsWith ("Dither.png")) {
                importer.textureFormat = TextureImporterFormat.RGBA32;
            }
        }
    
        // Floyd–Steinberg dithering实现参考:https://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering
        void OnPostprocessTexture (Texture2D texture)
        {
            if (!assetPath.EndsWith ("Dither.png")) {
                return;
            }
    
            var texw = texture.width;
            var texh = texture.height;
    
            var pixels = texture.GetPixels ();
            var offs = 0;
    
            var k1Per15 = 1.0f / 15.0f;
            var k1Per16 = 1.0f / 16.0f;
            var k3Per16 = 3.0f / 16.0f;
            var k5Per16 = 5.0f / 16.0f;
            var k7Per16 = 7.0f / 16.0f;
    
            for (var y = 0; y < texh; y++) {
                for (var x = 0; x < texw; x++) {
                    float a = pixels [offs].a;
                    float r = pixels [offs].r;
                    float g = pixels [offs].g;
                    float b = pixels [offs].b;
    
                    var a2 = Mathf.Clamp01 (Mathf.Floor (a * 16) * k1Per15);
                    var r2 = Mathf.Clamp01 (Mathf.Floor (r * 16) * k1Per15);
                    var g2 = Mathf.Clamp01 (Mathf.Floor (g * 16) * k1Per15);
                    var b2 = Mathf.Clamp01 (Mathf.Floor (b * 16) * k1Per15);
    
                    var ae = a - a2;
                    var re = r - r2;
                    var ge = g - g2;
                    var be = b - b2;
    
                    pixels [offs].a = a2;
                    pixels [offs].r = r2;
                    pixels [offs].g = g2;
                    pixels [offs].b = b2;
    
                    var n1 = offs + 1;   // (x+1,y)
                    var n2 = offs + texw - 1; // (x-1 , y+1)
                    var n3 = offs + texw;  // (x, y+1)
                    var n4 = offs + texw + 1; // (x+1 , y+1)
    
                    if (x < texw - 1) {
                        pixels [n1].a += ae * k7Per16;
                        pixels [n1].r += re * k7Per16;
                        pixels [n1].g += ge * k7Per16;
                        pixels [n1].b += be * k7Per16;
                    }
    
                    if (y < texh - 1) {
                        pixels [n3].a += ae * k5Per16;
                        pixels [n3].r += re * k5Per16;
                        pixels [n3].g += ge * k5Per16;
                        pixels [n3].b += be * k5Per16;
    
                        if (x > 0) {
                            pixels [n2].a += ae * k3Per16;
                            pixels [n2].r += re * k3Per16;
                            pixels [n2].g += ge * k3Per16;
                            pixels [n2].b += be * k3Per16;
                        }
    
                        if (x < texw - 1) {
                            pixels [n4].a += ae * k1Per16;
                            pixels [n4].r += re * k1Per16;
                            pixels [n4].g += ge * k1Per16;
                            pixels [n4].b += be * k1Per16;
                        }
                    }
    
                    offs++;
                }
            }
    
            texture.SetPixels (pixels);
            EditorUtility.CompressTexture (texture, TextureFormat.RGBA4444, TextureCompressionQuality.Best);
        }
    }
    

    效果对比

    mark
    mark

  • 相关阅读:
    JQ实现选项卡(jQuery原型插件扩展)
    jQuery的实现原理和核心
    fetch 关于七牛的content-type 的问题
    npm 安装远程包(github的)
    关于dvajs里effects的call和put
    babel6 的 export default bug
    regeneratorRuntime未定义
    babel 解构赋值无法问题
    npm 安装本地包
    datable-默认参数列表
  • 原文地址:https://www.cnblogs.com/zsb517/p/6322773.html
Copyright © 2011-2022 走看看