Creating atlas using CopyTexture

Hi,
I have a bunch of individual textures that I want (automatically) to copy into a bigger one by order to create a spritesheet (I need them in order, so i cant use Textures.Pack).
I initially wanted to use Graphics.CopyTexture, since it’s the one that lets me say in which specific part of the destination texture I want to copy each sprite (perfect for constructing a spritesheet).
However, I have found that CopyTexture only works on the GPU side, resulting in the sheet correctly showing on inspector:

But the image file is completely empty:

I think I can use Render Textures to then use Blit() after copying everything, but I’m not sure how, and I can’t find any docs.

Here is the code:

void GenerateSpritesheet()
    {
        string[] fileEntries = Directory.GetFiles(Application.dataPath + "/" + originPath, "*.png");
        List<Texture> allFrames = new List<Texture>();
        foreach (string fileName in fileEntries)
        {
            int index = fileName.LastIndexOf("/");
            string localPath = "Assets/" + originPath;

            if (index > 0)
                localPath += fileName.Substring(index);

            Texture t = (Texture)AssetDatabase.LoadAssetAtPath(localPath, typeof(Texture));

            if (t != null)
                allFrames.Add(t);
        }


        int size = Mathf.NextPowerOfTwo((int)Mathf.Sqrt((float)allFrames.Count)) * 512;

        //First, store the texture empty to have a texture importer
        Texture2D spritesheet = new Texture2D(size, size, TextureFormat.RGBA32, false);

        Byte[] png = spritesheet.EncodeToPNG();
        File.WriteAllBytes(Application.dataPath + "/" + spritesheetPath + animName + ".png", png);

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        spritesheet = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/" + spritesheetPath + animName + ".png");

        TextureImporter textureImporter = AssetImporter.GetAtPath("Assets/" + spritesheetPath + animName + ".png") as TextureImporter;
        textureImporter.textureType = TextureImporterType.Sprite;
        textureImporter.alphaIsTransparency = true;
        textureImporter.filterMode = FilterMode.Point;
        textureImporter.spriteImportMode = SpriteImportMode.Multiple;
        textureImporter.maxTextureSize = 8192;
        textureImporter.isReadable = true;

        textureImporter.SaveAndReimport();

        int x = 0;
        int y = spritesheet.width;
        foreach (Texture t in allFrames)
        {
            Graphics.CopyTexture(t, 0, 0, 0, 0, t.width, t.height, spritesheet, 0, 0, x, y - t.height);

            x += t.width;

            if (x >= spritesheet.width)
            {
                x = 0;
                y -= t.height;
            }
        }

        //spritesheet.Apply();
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

Do you mean to instantiate a texture2D and use texture.SetPixels()? I’ve generated spritesheets using that approach. There are loads of similar methods in the Texture API, some more efficient than others. This requires your source textures be read/write enabled.

You might also consider Unity’s built-in Sprite Atlas. It doesn’t work at runtime but works at editor time for most use cases.

That was another option, but since ReadPixels works with the image as one dimensional array, I’m not sure how I could build the code to copy a smaller texture into a specific part of a bigger atlas.

Didn’t know about it, seems like it will be a good solution!

Edit: SpriteAtlas work like a charm! Is better optimized than a handcrafted spritesheet, and you can work with the individual textures without doing any slicing. Perfect for what I need.