Speed Up Large Get and Set Pixel Operations?

I’m working on a function where I have two textures: 1 is an image, and another (of identical size) is a mask, with all clear pixels, except for certain areas. My goal is to use this mask texture to remove everything from the image except for the masked areas.
The following code works, but is very slow with larger images. I was wondering if anyone has any tips on speeding up this process or even an alternative that would be better.

// imageTex is the source image
// alphaMask is the mask

for (int x = 0; x < imageTex.width; x++)
{
    for (int y = 0; y < imageTex.height; y++)
    {
        Color maskPixel = alphaMask.GetPixel(x, y);

        if (maskPixel != Color.clear)
            continue;

        imageTex.SetPixel(x, y, Color.clear);
    }
}

newBG.Apply();

I need to be working directly with the textures so I can save them to disk, so I can’t think of a way other than Get/Set pixel.
Thanks!

After looking more into it, I wanted to jump back in on my own post and share that changing each Get/SetPixel call to Get/SetPixelS (plural), sped things up significantly.
For future Unity-nauts who need something similar, this is a good example on how you can migrate to Get/SetPixels for large operations.

// imageTex is the source image
// alphaMask is the mask
// Get the color data for both textures at once
Color[] imagePixels = imageTex.GetPixels();
Color[] maskPixels = alphaMask.GetPixels();
// Iterate over the pixels in the mask
for (int i = 0; i < maskPixels.Length; i++)
{
    // If the mask pixel is not clear, skip it
    if (maskPixels[i] != Color.clear)
        continue;
    // Otherwise, set the corresponding image pixel to clear
    imagePixels[i] = Color.clear;
}
// Set the color data for the image texture
imageTex.SetPixels(imagePixels);
imageTex.Apply();

And if you’re just blasting pixels INTO a texture, you don’t have to keep asking for them back with .GetPixels()… just get them once, keep the array, update the array, call SetPixels / Apply it back.

Or if you feel brave, pin the color array and pass it into a native C function that can be your own super-ultra-turbo-optimized software blitter / rasterizer, then unpin it and shove it into the texture.

That’s how my KurtMaster2D game does it for all my old MS-DOS games.

Pinning a texture for manipulation via native code:

KurtMaster2D is free here:

Apple iTunes: ‎KurtMaster2D on the App Store

Google Play: https://play.google.com/store/apps/details?id=com.plbm.plbm1

2 Likes

I’ll look into that, thanks for the suggestions!

Whenever I need to do image manipulation in Unity I usually turn to shaders and rendertextures, so don’t forget about these!

1 Like

I appreciate the suggestion! I’ve looked into those, but the problem is, I need to save the texture to disk, so using shaders won’t quite work. And for Render Textures, I’m not quite sure how to best do this.

I’m also gonna try to switch to GetPixels32 as I heard its even faster as well.

If you use a Shader to do your ‘calculation’ (i.e. the checking for Color.clear in your mask) you can render the result to a RenderTexture, then do a GetPixels() on that rendertexture to get the output that you want to write to disk.

public class SaveRenderTextureToFile {
    [MenuItem("Assets/Save RenderTexture to file")]
    public static void SaveRTToFile()
    {
        RenderTexture rt = Selection.activeObject as RenderTexture;

        RenderTexture.active = rt;
        Texture2D tex = new Texture2D(rt.width, rt.height, TextureFormat.RGB24, false);
        tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
        RenderTexture.active = null;

        byte[] bytes;
        bytes = tex.EncodeToPNG();
       
        string path = AssetDatabase.GetAssetPath(rt) + ".png";
        System.IO.File.WriteAllBytes(path, bytes);
        AssetDatabase.ImportAsset(path);
        Debug.Log("Saved to " + path);
    }

    [MenuItem("Assets/Save RenderTexture to file", true)]
    public static bool SaveRTToFileValidation()
    {
        return Selection.activeObject is RenderTexture;
    }
}
4 Likes

Thanks for the example, I appreciate it!

Hi, I am also working on painting pixels on textures. Can you give a full working example of shader for efficiently manipulation of texture pixels at runtime?
Thanks.