Bootstrap

合并场景中多个单元图(sprite)

如果场景中存在很多物体,电脑会变得卡顿甚至程序崩溃,合并为一张图可以节约性能。
在这里插入图片描述
在这里插入图片描述

using UnityEditor;
using System.IO;

public Transform[] Boundarys;  //合并图像的边界,用来选取左下点和右上点,确定合并图像的大小
public List<Transform> My_Units;  //单元图的集合,必须位于边界内,没有图片也行,主要功能为记录位置
public Prefab_Unit;  //单元图的模板,用以提取texture进行复制,(运行功能前,需要将其sprite,在属性面板改为可读,否则将报错)
public SpriteRenderer My_CombineSprite;  //合并图像的载体

    //***********************************************************************************   Combine
    [ContextMenu("TextureCombine")]
    void Combine()
    {
        //*****************  确定长宽

        float width, height;
        Vector2 v_ld = new Vector2(100, 100);
        Vector2 v_ru = new Vector2(0, 0);

        for (int i = 0; i < Boundarys.Length; i++)
        {
            if (Boundarys[i].transform.position.x < v_ld.x)
                v_ld.x = Boundarys[i].transform.position.x;
            if (Boundarys[i].transform.position.x > v_ru.x)
                v_ru.x = Boundarys[i].transform.position.x;
            if (Boundarys[i].transform.position.y < v_ld.y)
                v_ld.y = Boundarys[i].transform.position.y;
            if (Boundarys[i].transform.position.y > v_ru.y)
                v_ru.y = Boundarys[i].transform.position.y;
        }
        width = v_ru.x - v_ld.x;
        height = v_ru.y - v_ld.y;


        //*****************  拼合

        int pix_width = (int)(width * 1000);     //   其中的1000为场景中实际距离和像素的比例
        int pix_height = (int)(height * 1000);

        Texture2D oTex = Prefab_Unit.GetComponent<SpriteRenderer>().sprite.texture;
        Texture2D targetTex = new Texture2D(pix_width, pix_height);
        for (int i = 0; i < targetTex.width; i++)
        {
            for (int j = 0; j < targetTex.height; j++)
            {
                targetTex.SetPixel(i, j, new Color(0f, 0f, 0f, 0f));
            }
        }
        Vector2 v_rela;
        Vector2Int v_pix_rela;
        Color color;
        for (int i = 0; i < My_Units.Count; i++)
        {
            v_rela = (Vector2)My_Units[i].transform.position - v_ld;
            v_pix_rela = new Vector2Int((int)(v_rela.x * 1000 - oTex.width / 2), (int)(v_rela.y * 1000 - oTex.height / 2));

            for (int q = 0; q < oTex.width; q++)
            {
                for (int p = 0; p < oTex.height; p++)
                {
                    color = Superpose_Color(targetTex.GetPixel(q + v_pix_rela.x, p + v_pix_rela.y), oTex.GetPixel(q, p));
                    targetTex.SetPixel(q + v_pix_rela.x, p + v_pix_rela.y, color);
                }
            }
        }
        targetTex.Apply();

        string path = "Assets/out.png";

        File.WriteAllBytes(path, targetTex.EncodeToPNG());
        AssetDatabase.Refresh();

        TextureImporter ti = AssetImporter.GetAtPath(path) as TextureImporter;
        ti.spritePixelsPerUnit = 1000;    //     根据实际情况,调整资源的像素比例
        AssetDatabase.ImportAsset(path);
        //****************  安放位置

        My_CombineSprite.sprite = AssetDatabase.LoadAssetAtPath<Sprite>(path);
        My_CombineSprite.transform.position = (v_ld + v_ru) / 2;

    }
	 // 返回叠加的像素颜色,但该方法很烂,只能勉强处理完全透明和完全不透明的图片
    Color Superpose_Color(Color c01,Color c02)   //c01为前置像素,c02为后置像素
    {
        float show_rata = (1f - c01.a) * c02.a;
        Color c03;
        if (show_rata > 0.9f)
            c03 = c02;
        else
            c03 = new Color(c01.r + c02.r * show_rata, c01.g + c02.g * show_rata, c01.b + c02.b * show_rata, show_rata + c01.a);

        return c03;
    }
    

小结:
1.这些都是在网上查找资料,拼合在一起的代码,效果还算可以,但叠加像素颜色的方法是自己瞎写的,只能勉强处理完全透明和完全不透明的像素颜色,可能存在问题,最好找一找另外的方法。
2.单元图的叠加,也会存在先后和遮挡的问题,所以还需另外添加单元图排序的代码。
3.代码中的数值1000可改变,若运行上述功能时太卡而导致崩溃,可将其调低,比如100
4.该代码,只能合并同种图片,即模板的单元图,若要合并多个不同的图片,需适当修改代码,但原理不变,依旧是提取texture,然后写入新texture。

;