纹理贴图的压缩算法

287 阅读1分钟

在Unity移动平台的游戏开发过程中,贴图资源是往往是占资源量最大的资源。如何在保证视觉效果的同时,尽可能地减少贴图资源,是开发团队会经常遇到的问题。通常来说,对于3D物体的纹理,是可以采用ETC/PVRTC等压缩比很大的算法处理,但是对于细节要求很高的UI纹理,这样处理造成的失真往往达不到质量要求。我们可以通过Dither565压缩算法对纹理贴图进行压缩,其本质是通过颜色抖动来避免产生类似RGB 16bit会产生的色阶问题,其好处是把这些噪点控制在人眼识别不出来的程度,这样的压缩效果就不会导致纹理美术品质的下降。具体算法代码实现如下: 

    public static void CompresseTexture(Texture2D texture)

    {

        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;//2的5次方

        var k_g = 64;

 

        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 * k5Per32;

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

    }