Trying to Apply a screenshot to a raw image, only works on second try...

I’m at the point in my (tabletop simulator) project where I’m doing the team setup system. The player enters a name, type, other unit info in the fields on the unit setup screen. They choose a model by toggling between different units in the scene, and a secondary camera shows the unit in a raw image on that screen. They choose the material they want the unit to have, click create and then this CreateUnitCard() function is called. This will instantiate a new UI prefab which will show the name, type, other info and a screenshot of that unit.I watched a Code Monkey video to learn how to take a screenshot, I have to admit I don’t 100% understand it.

The problem is not in the actual screenshot taking, I don’t think – It pops up in the resources folder and looks fine to me. I have noticed that I need to click off of unity and reselect the program before it becomes visible, but it is there. The screenshot just doesn’t get applied to the raw image on the unit card. That remains white. Texture is: None (Texture).

The Screenshot function saves an image and names it after the unit. I have noticed that if I create a unit with a name that matches an image already saved to the resources folder, it does work. So If I try to make “Bob” his screenshot will be saved to the resources folder, but it will not display the screenshot on his card. If I then exit play mode, get back in and try to make “Bob” again, it will work as intended.
If anyone could shine some light on this issue I would greatly appreciate it!

Here’s the CreateUnitCard function-

    public void CreateUnitCard()
    {
        
        GameObject newCard = Instantiate(unitCard, TeamPanel.transform.position, transform.rotation);
        newCard.transform.SetParent(TeamPanel.transform);

        Text nameLine = newCard.gameObject.transform.Find("NameText").GetComponent<Text>();
        nameLine.text = unitName;

        Text typeLine = newCard.gameObject.transform.Find("TypeText").GetComponent<Text>();
        typeLine.text = unitType;

        Text otherInfoLine = newCard.gameObject.transform.Find("OtherInfoText").GetComponent<Text>();
        otherInfoLine.text = otherUnitInfo;

        ScreenshotHandler.TakeScreenshot(200, 300, unitName);
        
        Texture2D UnitPhoto = Resources.Load<Texture2D>(unitName);
        RawImage unitImageHolder = newCard.gameObject.transform.Find("Thumbnail").GetComponent<RawImage>();
        unitImageHolder.texture = UnitPhoto;

        //Reset text variables
    }

AND this is the Code Monkey script I’m using -

public class ScreenshotHandler : MonoBehaviour
{
    private static ScreenshotHandler instance;

    [SerializeField] 
    Camera myCamera;
    private bool takeScreenshotOnNextFrame;
    static string unitName;


    private void Awake()
    {
        instance = this;
    }

    private void OnPostRender()
    {
        if (takeScreenshotOnNextFrame)
        {
            takeScreenshotOnNextFrame = false;
            RenderTexture renderTexture = myCamera.targetTexture;

            Texture2D renderResult = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.RGB24, false);
            Rect rect = new Rect(0, 0, renderTexture.width, renderTexture.height);
            renderResult.ReadPixels(rect, 0, 0);
            
            byte[] byteArray = renderResult.EncodeToPNG();
            System.IO.File.WriteAllBytes(Application.dataPath + "/Resources/" + unitName + ".png", byteArray);
            Debug.Log("Saved Screenshot " + unitName + ".png");

            RenderTexture.ReleaseTemporary(renderTexture);
            myCamera.targetTexture = null;
        }
    }

    private void TakeScreenshot(int width, int height)
    {
        myCamera.targetTexture = RenderTexture.GetTemporary(width, height, 16);
        takeScreenshotOnNextFrame = true;
    }
    public static void TakeScreenshot(int width, int height, string name)
    {
        unitName = name;
        instance.TakeScreenshot(width, height);
    }
}

This is the create a unit menu -

And here’s the main unity window, showing that the unit card is there, the create unit function has run, the image has saved but it was not applied to the Raw Image on the card-

If you have read this far, you are awesome. Thanks for any help!

It looks like you try to assign your texture (Screenshot) before the screenshot got taken and saved.
If you look at the code in your ScreenshotHandler , you see that the Screenshot gets taken in the next frame. That means that the Texture does not yet exist when you try to assign it.
One simple fix should be the following:
Put the code that assigns the texture to your card into a Coroutine, like so:

private IEnumerator AssignTextureToCard()
{
    yield return 0;
    yield return new WaitForEndOfFrame();

    Texture2D UnitPhoto = Resources.Load<Texture2D>(unitName);
    RawImage unitImageHolder = newCard.gameObject.transform.Find("Thumbnail").GetComponent<RawImage>();
    unitImageHolder.texture = UnitPhoto;

    //Reset text variables
}

Call this Coroutine after Line 16 in your first script, like so: StartCoroutine(AssignTextureToCard());

  1. This Coroutine waits one frame ( yield return 0; )
  2. In the next frame, it waits for the frame to end ( yield return new WaitForEndOfFrame(); )
  3. Then it assignes the Texture to your card

This is necessary because of Unity’s Execution Order (click here for more information).
We do yield return 0 to make sure we are in the same frame as when the Screenshot gets taken.
With yield return new WaitForEndOfFrame(); we make sure that the Screenshot is actually taken and saved, before we try to access it (See in the Execution Order how the Screen gets rendered, before yield WaitForEndOfFrame )
alt text