Run Unity standalone in Headless Mode whilst capturing screenshots

╄→尐↘猪︶ㄣ 提交于 2020-12-04 05:24:30

问题


I need to create a unity project which runs in Headless mode (using the -batchmode command), but it must capture screenshots e.g. every one second and write them out to a file.

I understand that in headless mode you need to forcefully call Camera.Render() in order for anything to be rendered.

It seems that time freezes after the first screenshot is captured. The first screenshot looks absolutely correct, but all subsequent screenshots are identical to the first, implying that time has frozen.

What do I need to do to ensure that the scene updates correctly over time and that the camera is able to render every second?

using System;
using System.Collections;
using System.IO;
using UnityEngine;

namespace Assets
{
    public class Particles : MonoBehaviour
    {
        private const float screenshotEvery = 1.0f;
        private float timerCount = 0f;
        private float elapsedSecond;
        private const float maxElapsedSecond = 20;
        private string screenshotsDirectory = "UnityHeadlessRenderingScreenshots";
        public Camera camOV;
        public RenderTexture currentRT;

        // Use this for initialization
        public void Start ()
        {
            Application.targetFrameRate = 60;
            if (Directory.Exists(screenshotsDirectory))
            {
                Directory.Delete(screenshotsDirectory, true);
            }
            if (!Application.isEditor)
            {
                Directory.CreateDirectory(screenshotsDirectory);
                camOV.targetTexture = currentRT;
            }

        }

        // Update is called once per frame
        public void Update ()
        {
            elapsedSecond += Time.deltaTime;
            timerCount += Time.deltaTime;
            if (Application.isEditor)
            {
                return;
            }
            if (elapsedSecond <= maxElapsedSecond)
            {
                if (timerCount >= screenshotEvery)
                {
                    TakeScreenShot();
                    timerCount = 0f;
                }
            }
            else
            {
                Application.Quit();
            }
        }

        public void TakeScreenShot()
        {
            RenderTexture.active = camOV.targetTexture;
            camOV.Render();
            Texture2D imageOverview = new Texture2D(camOV.targetTexture.width, camOV.targetTexture.height, TextureFormat.RGB24, false);
            imageOverview.ReadPixels(new Rect(0, 0, camOV.targetTexture.width, camOV.targetTexture.height), 0, 0);
            imageOverview.Apply();
            RenderTexture.active = currentRT;

            // Encode texture into PNG
            byte[] bytes = imageOverview.EncodeToPNG();

            // save in memory
            string filename = elapsedSecond + ".png";
            var path = screenshotsDirectory + "/" + filename;
            File.WriteAllBytes(path, bytes);

        }
    }
}

Many thanks in advance!


回答1:


One advice I would give you about taking screenshots is to wait for WaitForEndOfFrame before taking the screenshot.

You said that you want to capture screenshot every second and save this. This should be done in coroutine not in the Update function.

Something like this in a coroutine function:

WaitForEndOfFrame waitForFrame = new WaitForEndOfFrame();
WaitForSeconds waitForTime = new WaitForSeconds(1);//1 second

while (true)
{
    //Wait for frame
    yield return waitForFrame;

    Increment timer

    Capture and save Screenshot

    Save the screenshot

    //Wait for one second 
    yield return waitForTime;
}

I did not encounter any problems by doing it this. Just start the coroutine and let it run forever in a while loop. It won't freeze because it is yielding every 1 second and also every frame. Below is the complete code:

public Camera camOV;
public RenderTexture currentRT;
float elapsedSecond = 0;
string screenshotsDirectory = "UnityHeadlessRenderingScreenshots";
float beginTime;

void Start()
{
    beginTime = Time.time;
    StartCoroutine(TakeScreenShot());
}

public IEnumerator TakeScreenShot()
{
    beginTime = Time.time;

    WaitForEndOfFrame waitForFrame = new WaitForEndOfFrame();
    WaitForSeconds waitForTime = new WaitForSeconds(1);//1 second

    while (true)
    {
        //Wait for frame
        yield return waitForFrame;

        //Increment timer
        elapsedSecond = Time.time - beginTime;

        RenderTexture.active = camOV.targetTexture;
        camOV.Render();
        Debug.Log(camOV);
        Texture2D imageOverview = new Texture2D(camOV.targetTexture.width, camOV.targetTexture.height,
            TextureFormat.RGB24, false);
        imageOverview.ReadPixels(new Rect(0, 0, camOV.targetTexture.width, camOV.targetTexture.height), 0, 0);
        imageOverview.Apply();
        RenderTexture.active = currentRT;

        // Encode texture into PNG
        byte[] bytes = imageOverview.EncodeToPNG();

        // save in memory
        string filename = elapsedSecond + ".png";
        var path = screenshotsDirectory + "/" + filename;
        File.WriteAllBytes(path, bytes);

        //Wait for one second 
        yield return waitForTime;

        Debug.Log(elapsedSecond);
    }
}


来源:https://stackoverflow.com/questions/44071756/run-unity-standalone-in-headless-mode-whilst-capturing-screenshots

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!