Texture原理及实时绘制

序言

序言看这里。

Texture是什么

在Unity中,图片导入后就是一个Texture,常用Texture Type为Sprite(精灵),也是在UI中Image组件需要的Texture类型。

Texture和Image Sprite的关系

    public Image image;
    public Texture2D texture;
    // Start is called before the first frame update
    void Start()
    {
       Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
       image.sprite = sprite; 
    }

上述代码会在游戏运行时,将拖拽到面板上的texture转换为Sprite再复制给UI中的Image组件,总结来说,一个png/jpg格式的图片导入Unity后会转变为Texture,Texture可以转变Type(默认Default)为Sprite精灵给UI用。

Texture和模型材质贴图的关系

模型的贴图由MeshRender下的Materials决定,材质的Albedo属性(主纹理/模型表面贴图)即一个Texture。

meshRenderer.sharedMaterial.mainTexture = texture;

通过这句代码修改DefaultMaterial会发现所有使用默认材质的物体贴图都已修改,另外材质的修改在运行时结束时仍会保存,可以通过在使用材质之前先Instantiate实例化一个对象间接调用避免直接使用资源。

alt

Texture实时改色以及叠加绘制

改色

Texture实际是由一个个像素点组成的,Unity中通过Colors结构体一维数组将像素值拉成一行保存。

        Color[] colors = texture.GetPixels();
        Debug.Log(colors.Length == 1928 * 1119);
        Debug.Log(colors.Length == texture.width * texture.height);
        Debug.Log(colors[0]);

可以看到color数组的长度和像素长*宽一致,第一个像素值为黑色(不同图片左下角第一个像素点)。 alt

    IEnumerator Test()
    {
        for (int i = 1; i <= 20; i++)
        {
            yield return new WaitForSeconds(1f);
            for (int x = 0; x < texture.width; x++)
            {
                for (int y = 0; y < 10*i; y++)
                {
                    texture.SetPixel(x, y, Color.blue);
                }
            }
            texture.Apply();
        }
    }

通过以上代码可以实现对Texture进行逐行改色,修改结果退出运行时仍会保存(特性),可以通过对Texture进行任意设置恢复原先状态。

alt

        for (int x = 0; x < texture.width; x++)
        {
            for (int y = 0; y < texture.height; y++)
            {
                if (texture.GetPixel(x,y) == Color.black)
                {
                    texture.SetPixel(x, y, Color.red);
                }
            }
        }
        texture.Apply();

通过以上代码可以将黑色像素值转换为红色,本质都是对像素点Pixel操作(结合协程可以实现血条效果)。 alt

叠加绘制

alt

在图片中间叠加画一张图,首先确定外框中心点,再确定所画图片的长宽。

        int startX = texture.width/2 - texture2.width / 2;
        int startY = texture.height/2 - texture2.height / 2;

        for (int x = 0; x < texture2.width; x++)
        {
            for (int y = 0; y < texture2.height; y++)
            {
                texture.SetPixel(startX + x, startY + y,texture2.GetPixel(x,y));              
            }
            texture.Apply();
            yield return new WaitForSeconds(0.01f);

alt