Search Unity

Merge textures from ui-images with color

Discussion in 'Scripting' started by juri-babarov, Oct 24, 2021.

  1. juri-babarov

    juri-babarov

    Joined:
    Jul 2, 2017
    Posts:
    2
    Hi,

    I'm building an editor for a 2d avatar with UI Images, where I change the sprite and color out of a list with different options.

    Here is an example:
    upload_2021-10-24_22-43-3.png

    The problem is to save the images as one png-file.

    I tried to create a new texture with ReadPixels from screen like the screenshot example from the docs:
    Code (CSharp):
    1. Texture2D texture = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
    2.        
    3. texture.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0, false);
    4. texture.Apply();
    5.  
    6. byte[] bytes = texture.EncodeToPNG();
    7. File.WriteAllBytes(Application.persistentDataPath + "/avatar.png", bytes);
    With this method the result image is dependent of the screensize and not the source sprites of 1024x1024px. So I get e.g. 357x659px images.

    Another approach was to get the source textures and lerp all the pixels:
    Code (CSharp):
    1. Texture2D texture = new Texture2D(texture_1.width, texture_1.height);
    2.  
    3. for (int i = 0; i < texture.width; i++)
    4. {
    5.     for (int j = 0; j < texture.height; j++)
    6.     {
    7.         Color tex1_color = texture_1.GetPixel(i, j);
    8.         Color tex2_color = texture_2.GetPixel(i, j);
    9.         Color merged_color = Color.Lerp(tex1_color, tex2_color, tex2_color.a / 1);
    10.  
    11.         texture.SetPixel(i, j, merged_color);
    12.     }
    13. }
    14.  
    15. texture.Apply();
    16.  
    17. byte[] bytes = texture.EncodeToPNG();
    18. File.WriteAllBytes(Application.persistentDataPath + "/avatar.png", bytes);
    But with this method the original colors of the sprites (in this case all default white) are saved and not the colors of the ui image component which is customized. And because there are about 15 images it takes some time to merge all one after another.

    Is there a possibility to save the sprites with the color from image component to a single png with original size of the sprites?
     

    Attached Files:

  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    Can you just check what color has been set on the image, and multiply by that color in the script?
     
  3. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    Easiest would probably be a render texture but I'm not sure wether it also renders GUI elements properly. But could be worth a look.
     
  4. juri-babarov

    juri-babarov

    Joined:
    Jul 2, 2017
    Posts:
    2
    Thanks for the replies!

    With multiplying the color I didn't get it to work and would have to lerp again every image, which was very slow.
    I got a solution now with RenderTexture that captures also the UI.

    Create a RenderTexture in the assets.
    In the scene I added a Camera with TargetTexture of the RenderTexture and transparent color for background.
    Move the UI Panel to a separate Canvas, which is Screen Space - Camera.
    Create a plane in the scene with the Render Texture applied so the main camera shows something for the player.

    And added a script on the camera where I just set a bool to true, if needed:
    Code (CSharp):
    1. public class CameraRender : MonoBehaviour
    2. {
    3.     public bool RenderNow;
    4.     public int ImageWidth = 1024;
    5.     public int ImageHeight = 1024;
    6.     public RenderTexture renderTexture;
    7.  
    8.     private void OnPostRender()
    9.     {
    10.         if (RenderNow)
    11.         {
    12.             Texture2D tex = new Texture2D(ImageWidth, ImageHeight, TextureFormat.ARGB32, false);
    13.  
    14.             RenderTexture.active = renderTexture;
    15.  
    16.             tex.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0, false);
    17.             tex.Apply();
    18.  
    19.             byte[] bytes = tex.EncodeToPNG();
    20.  
    21.             Destroy(tex);
    22.             renderTexture.Release();
    23.  
    24.             File.WriteAllBytes(Application.persistentDataPath + "/avatar.png", bytes);
    25.  
    26.             RenderNow = false;
    27.         }
    28.     }
    29. }
    30.  
     
    exiguous likes this.