Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resulting screenshot/image in game is upside down and not correctly positioned

Discussion in 'Editor & General Support' started by jra8908, Mar 17, 2020.

  1. jra8908

    jra8908

    Joined:
    Apr 1, 2018
    Posts:
    7
    Hi!

    So I'm making a function for my game where the player can press a little camera button and it takes a picture of their character that they can then save (it's a dress up game). Taking the picture and so on works and is fine, but I wanted to make it easier for me to position the area where the picture is to be taken; and this is where I'm having problems.

    EDIT: My solution for now is to use a package from the Asset store called "Screenshot companion" which solved my issue. The displacement of the image is still an issue but I simply moved the GameObject to make up for that temporarily.

    I created a GameObject and added a Rect Transform to it, then I position this over the character and then in my code I fetch this Rect Transform and use the position values to take the picture. The problem is that where I position the Rect in the Editor ALMOST represents where the picture is taken and I really can't seem to get it right. It's enough out of place to bug me. I can make up for it and position it differently so the output picture looks good, but I'm not satisfied with that. I don't like unexpected results like this...

    So here's my code (This is the latest attempt that worked the best)
    Code (CSharp):
    1.     public void SavePicture()
    2.     {
    3.         rect = gameObject.GetComponent<RectTransform>();
    4.         var width = (int)Screen.width;
    5.         var height = (int)Screen.height;
    6.  
    7.         RenderTexture rt = new RenderTexture(width, height, 0);
    8.         ScreenCapture.CaptureScreenshotIntoRenderTexture(rt);
    9.         RenderTexture.active = rt;
    10.         Texture2D screenshot = new Texture2D((int)rect.rect.width,  (int)rect.rect.height, TextureFormat.RGB24, false);
    11.  
    12.         screenshot.ReadPixels(new Rect(rect.transform.position.x, rect.transform.position.y, rect.rect.width, rect.rect.height), 0, 0);
    13.         screenshot.Apply();
    14.         byte[] bytes = screenshot.EncodeToPNG();
    15.         System.IO.File.WriteAllBytes("weee.png", bytes);
    16.         RenderTexture.active = null;
    17.         DestroyImmediate(rt);
    18.     }
    I have attached two images. One is the resulting image (It's upside down, not sure why), and one is a screenshot from the editor showing the Rect Transform and where I positioned it. I've been thinking if maybe it's actually correctly positioned, but the fact that it's upside down makes it become like this?


    Screenshot
    screenshot.png



    Editor
    Editor.png

    Does anyone have any wise words to guide me? : )

    Thanks in advance!
     
    Last edited: Mar 18, 2020
  2. Rafael_CS

    Rafael_CS

    Joined:
    Sep 16, 2013
    Posts:
    160
    When capturing image from screen you must take care with graphic device type.

    In OpenGL the image will be bottom-up (exactly like unity handle it) but in other operational systems the image will be Top-down.

    https://docs.unity3d.com/Manual/SL-PlatformDifferences.html

    var flipY = graphicDevice == GraphicsDeviceType.OpenGLCore ||
    graphicDevice == GraphicsDeviceType.OpenGLES2 ||
    graphicDevice == GraphicsDeviceType.OpenGLES3 ||
    graphicDevice == GraphicsDeviceType.Vulkan ?
    false :
    true;
     
    Last edited: Apr 5, 2021
    Joe-Censored likes this.
  3. Dreamback

    Dreamback

    Joined:
    Jul 29, 2016
    Posts:
    220
    But...what do you do with the results of that? How do you tell ScreenCapture.CaptureScreenshotIntoRenderTexture or screenshot.ReadPixels or whatever is causing the problem to flip the results?
     
    deus0 likes this.
  4. Rafael_CS

    Rafael_CS

    Joined:
    Sep 16, 2013
    Posts:
    160
    you must handle it by yourself, using a custom shader to flip image (with Graphics.Blit + Custom Shader) or reading image in inverse Y Order (when using readpixels)
     
    Joe-Censored likes this.
  5. deus0

    deus0

    Joined:
    May 12, 2015
    Posts:
    256
    Hey, I was trying to figure out a way to write to the file while in a ecs job... but got distracted with screenshot code. Here was a solution I wrote! I'm using vulkan so this flips the pixels vertically!

    I also posted some screenshots I took during.. haha
    https://twitter.com/deusxyz/status/1416846683376218117

    Really happy unity has these new texture functions!

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Rendering;
    3. using Unity.Collections;
    4. using System;
    5. using System.IO;
    6. using System.Collections;
    7.  
    8. public class CaptureScreen : MonoBehaviour
    9. {
    10.     public static CaptureScreen instance;
    11.     public string filePath;
    12.  
    13.     void Awake()
    14.     {
    15.         instance = this;
    16.     }
    17.  
    18.     public void Capture()
    19.     {
    20.         StartCoroutine(AsyncCapture());
    21.     }
    22.  
    23.     IEnumerator AsyncCapture()
    24.     {
    25.         yield return new WaitForEndOfFrame();
    26.         var rt = RenderTexture.GetTemporary(Screen.width, Screen.height, 0, RenderTextureFormat.ARGB32);
    27.         ScreenCapture.CaptureScreenshotIntoRenderTexture(rt);
    28.         AsyncGPUReadback.Request(rt, 0, TextureFormat.RGBA32, OnCompleteReadback);
    29.         RenderTexture.ReleaseTemporary(rt);
    30.     }
    31.  
    32.     void OnCompleteReadback(AsyncGPUReadbackRequest asyncGPUReadbackRequest)
    33.     {
    34.         // get screenshot data as nativearray or handle error
    35.         if (asyncGPUReadbackRequest.hasError)
    36.         {
    37.             Debug.LogError("Error Capturing Screenshot: With AsyncGPUReadbackRequest.");
    38.             return;
    39.         }
    40.         var rawData = asyncGPUReadbackRequest.GetData<byte>();
    41.         // Grab screen dimensions
    42.         var width = Screen.width;
    43.         var height = Screen.height;
    44.         var texture = new Texture2D(width, height, TextureFormat.RGBA32, false);
    45.         var processedData = texture.GetRawTextureData<byte>();
    46.         // now flip vertical pixels
    47.         for (int i = 0; i < rawData.Length; i += 4)
    48.         {
    49.             var arrayIndex = i / 4;
    50.             var x = arrayIndex % width;
    51.             var y = arrayIndex / width;
    52.             var flippedY = (height - 1 - y);
    53.             var flippedIndex = x + flippedY * width;
    54.             // flip the data
    55.             processedData[i] = rawData[flippedIndex * 4];
    56.             processedData[i + 1] = rawData[flippedIndex * 4 + 1];
    57.             processedData[i + 2] = rawData[flippedIndex * 4 + 2];
    58.             processedData[i + 3] = rawData[flippedIndex * 4 + 3];
    59.         }
    60.         // create texture and save as png using datetime
    61.         var dateTime = DateTime.Now;
    62.         var dateTimeString = dateTime.ToString("-yyyy-MM-dd_") + dateTime.Hour + "h-" + dateTime.Minute + "m";
    63.         File.WriteAllBytes(filePath + dateTimeString + ".png", ImageConversion.EncodeToPNG(texture));
    64.         Destroy(texture);
    65.         // todo: hook this up with my twitter.py script
    66.     }
    67. }
     
    anksahu likes this.