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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM