I have a script PlayWebcam.cs attached to one game object, which captures the webcam image when I press a button or the Space bar, and saves it as a file in my Resources folder as "SavedScreen1".

Another script LoadTexture.cs is attached to a raw image and I want this texture to update in real time game play each time the button mentioned above is pressed.

At the moment, my first script does save the webcam screenshot to the Resources folder as a file, however, the second script does not update the saved image successfully, unless I stop the game and open the image file by double clicking on it, then press play again.

Ideally, I would like to be able to create multiple saved screen files not just one, and apply them to a number of different game objects or ui images each time the user saves a screenshot from the webcam by pressing the button.

I have tried various things like putting the load texture code in void Start and void Update, and in the PlayWebCam script itself, but nothing has worked so far.

public class PlayWebCam : MonoBehaviour

{
    WebCamTexture _webcamtex;    

    // Start is called before the first frame update
    void Start()
    {
        _webcamtex = new WebCamTexture();
        Renderer _renderer = GetComponent<Renderer>();
        _renderer.material.mainTexture = _webcamtex;
        _webcamtex.Play();
    }


    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            StartCoroutine(CaptureTextureAsPNG());
        }
    }

    public void OnClick()
    {
        StartCoroutine(CaptureTextureAsPNG());    
    }

     IEnumerator CaptureTextureAsPNG()
    {
        yield return new WaitForEndOfFrame();
        Texture2D _TextureFromCamera = new Texture2D(GetComponent<Renderer>().material.mainTexture.width,
        GetComponent<Renderer>().material.mainTexture.height);
        _TextureFromCamera.SetPixels((GetComponent<Renderer>().material.mainTexture as WebCamTexture).GetPixels());
        _TextureFromCamera.Apply();
        byte[] bytes = _TextureFromCamera.EncodeToPNG();
        string filePath = "Assets/Resources/SavedScreen1.png";
        File.WriteAllBytes(filePath, bytes);     
    }
}

AND....

public class LoadTexture : MonoBehaviour
{
    public Texture2D myTexture;

    // Use this for initialization
    void Start()
    {
        // load texture from resource folder
        myTexture = Resources.Load("SavedScreen1") as Texture2D;

        GameObject rawImage = GameObject.Find("RawImage");
        rawImage.GetComponent<RawImage>().texture = myTexture;
    }

     void Update()
    {
        // load texture from resource folder
        myTexture = Resources.Load("SavedScreen1") as Texture2D;

        GameObject rawImage = GameObject.Find("RawImage");
        rawImage.GetComponent<RawImage>().texture = myTexture;

    }
}

2 Answers

1
Draco18s On

Resources is a magic folder

As such, it does magic things.

The purpose of the folder is that anything inside of it is automatically included in the binary build. In the editor this means that when you click play the items in the folder are (effectively) cached and non-modifiable.

If you were to make a standalone build you would find that the ./Resources directory as a location ceases to exist and you can't write anything into it anyway! (And god only knows where your webcam textures will actually be written to with your current code).

If you want to reference files on the file system you have to use the Application.persistentDataPath as a known-safe-accessible location.

(But saving webcam textures here in order to render webcam footage is probably a bad idea anyway; that's what things like RenderTexture are for! Disc IO is SLOW)

0
Mark On

Ok, so at least before build, as I am still just experimenting with getting it working in Unity, it seems to be working if I swap out the LoadTexture script for this one, and set up a StreamingAssets folder where the saved screenshots are held. My next challenge is how to save multiple screenshots to this folder, and apply them sequentially onto objects or images in the scene. Any ideas appreciated.

void Start()
{

    DirectoryInfo directoryInfo = new DirectoryInfo(Application.streamingAssetsPath);
    print("Streaming Assets Path: " + Application.streamingAssetsPath);
    FileInfo[] allFiles = directoryInfo.GetFiles("*.*");
    foreach (FileInfo file in allFiles)
    {
        if (file.Name.Contains("player1"))
        {
            StartCoroutine("LoadPlayerUI", file);
        }          
    }     
}

IEnumerator LoadPlayerUI(FileInfo playerFile)
{
    //1
    if (playerFile.Name.Contains("meta"))
    {
        yield break;
    }
    //2
    else
    {
        string playerFileWithoutExtension = Path.GetFileNameWithoutExtension(playerFile.ToString());
        string[] playerNameData = playerFileWithoutExtension.Split(" "[0]);
        //3
        string tempPlayerName = "";
        int i = 0;
        foreach (string stringFromFileName in playerNameData)
        {
            if (i != 0)
            {
                tempPlayerName = tempPlayerName + stringFromFileName + " ";
            }
            i++;
        }
        //4
        string wwwPlayerFilePath = "file://" + playerFile.FullName.ToString();
        WWW www = new WWW(wwwPlayerFilePath);
        yield return www;
        //5
        playerAvatar.sprite = Sprite.Create(www.texture, new Rect(0, 0, www.texture.width, www.texture.height), new Vector2(0.5f, 0.5f));
        playerName.text = tempPlayerName;

    }

}

void Update()
{

    DirectoryInfo directoryInfo = new DirectoryInfo(Application.streamingAssetsPath);
    print("Streaming Assets Path: " + Application.streamingAssetsPath);
    FileInfo[] allFiles = directoryInfo.GetFiles("*.*");
    foreach (FileInfo file in allFiles)
    {
        if (file.Name.Contains("player1"))
        {
            StartCoroutine("LoadPlayerUI", file);
        }
    }

}