Unity Textureのコピーとソフトフィルター



RenderTextureに一度コピーしてから取得する。

```C#
Texture2D tar;
Texture2D dst = tar.Copy();
//Texture2D dst = tar.Copy(filter);
```


```C#
static class TextureCopyExtension
{
    public static Sprite ToSprite(this Texture2D tex)
    {
        return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
    }

    public static Texture2D Copy(this Texture2D source, System.Func<Color[], int, int, Color[]> filter = null)
    {

        var texture = new Texture2D(source.width, source.height, TextureFormat.RGBA32, false);
        var renderTexture = new RenderTexture(texture.width, texture.height, 32);

        // もとのテクスチャをRenderTextureにコピー
        Graphics.Blit(source, renderTexture);
        RenderTexture.active = renderTexture;

        // RenderTexture.activeの内容をtextureに書き込み
        texture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
        RenderTexture.active = null;
        // 不要になったので削除
        RenderTexture.DestroyImmediate(renderTexture);

        if (filter != null)
        {
            var pixels = filter(texture.GetPixels(), texture.width, texture.height);
            texture.SetPixels(pixels);
            texture.Apply();
        }

        return texture;
    }

}//class
```

```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class filter : MonoBehaviour
{

    [SerializeField] Texture2D _tex;
    // Start is called before the first frame update
    void Start()
    {
        gameObject.GetComponent<Image>().sprite = _tex
         //.Copy(filter_grayscale)
         //.Copy(filter_dither)
         //.Copy(filter_blue)
         .Copy(filter_gamma)
         .ToSprite()
         ;

    }
    Color[] filter_grayscale(Color[] data, int w, int h)
    {
        for (var i = 0; i < data.Length; i++)
        {
            int x = i % h, y = i / w;
            float c = (data[i].r + data[i].g + data[i].b) / 3.0f;
            data[i] = new Color(c,c,c, data[i].a);
        }
        return data;
    }

    Color[] filter_dither(Color[] data, int w, int h)
    {

        int[,] bayer ={
         {0 * 16 + 8, 8 * 16 + 8, 2 * 16 + 8, 10 * 16 + 8},
         {12 * 16 + 8, 4 * 16 + 8, 14 * 16 + 8, 6 * 16 + 8},
         {3 * 16 + 8, 11 * 16 + 8, 1 * 16 + 8, 9 * 16 + 8},
         {15 * 16 + 8, 7 * 16 + 8, 13 * 16 + 8, 5 * 16 + 8}
        };
        int x, y, chk, wk, gain = 255;

        for (var i = 0; i < data.Length; i++)
        {
            wk = (i / 4);
            y = (wk / w);
            x = (wk % w);
            chk = bayer[x % 4, y % 4];
            var r = (data[i].r * gain >= chk) ? 1 : 0;
            var g = (data[i].g * gain >= chk) ? 1 : 0;
            var b = (data[i].b * gain >= chk) ? 1 : 0;
            data[i] = new Color(r,g,b, data[i].a);

        }
        return data;
    }

    Color[] filter_blue(Color[] data, int w, int h)
    {
        float f(float d) => Mathf.Min(d, 1);
        for (var i = 0; i < data.Length; i++)
        {
            // (r+g+b)/3
            float c = (data[i].r + data[i].g + data[i].b) / 3.0f;
            var r=c;
            var g=f(c + c * 0.25f);
            var b=f(c + c * 0.5f);
            data[i] = new Color(r,g,b, data[i].a);
        }
        return data;
    }

    Color[] filter_gamma(Color[] data, int w, int h){
        // 補正値（1より小さい:暗くなる、1より大きい明るくなる）
        var gamma = 0.8f;//2.0f;
        // 補正式
        float correctify(float val) => Mathf.Pow(val, 1 / gamma);

        for (var i = 0; i < data.Length; i++)
        {
            var r = correctify(data[i].r);
            var g = correctify(data[i].g);
            var b = correctify(data[i].b);
            data[i] = new Color(r,g,b,data[i].a);
        }

        return data;
    }


}//class




static class TextureCopyExtension
{
    public static Sprite ToSprite(this Texture2D tex)
    {
        return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
    }

    public static Texture2D Copy(this Texture2D source, System.Func<Color[], int, int, Color[]> filter = null)
    {

        var texture = new Texture2D(source.width, source.height, TextureFormat.RGBA32, false);
        var renderTexture = new RenderTexture(texture.width, texture.height, 32);

        // もとのテクスチャをRenderTextureにコピー
        Graphics.Blit(source, renderTexture);
        RenderTexture.active = renderTexture;

        // RenderTexture.activeの内容をtextureに書き込み
        texture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
        RenderTexture.active = null;
        // 不要になったので削除
        RenderTexture.DestroyImmediate(renderTexture);

        if (filter != null)
        {
            var pixels = filter(texture.GetPixels(), texture.width, texture.height);
            texture.SetPixels(pixels);
            texture.Apply();
        }

        return texture;
    }

}//class
```