在无头模式下运行Unity独立,同时捕获屏幕截图

时间:2017-05-19 13:47:16

标签: c# unity3d camera rendering headless

我需要创建一个在Headless模式下运行的Unity项目(使用-batchmode命令),但它必须捕获屏幕截图,例如每一秒将它们写入文件。

我知道在无头模式下你需要强行调用Camera.Render()以便渲染任何东西。

在捕获第一个屏幕截图后,似乎时间冻结了。第一个屏幕截图看起来绝对正确,但所有后续屏幕截图都与第一个截图相同,这意味着时间已经冻结。

我需要做些什么来确保场景随着时间的推移正确更新并且相机能够每秒渲染一次?

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);

        }
    }
}

非常感谢提前!

1 个答案:

答案 0 :(得分:2)

我会给你一些关于截屏的建议是在拍摄截图之前等待WaitForEndOfFrame

你说你想每秒捕捉截图并保存。这应该在协程中完成而不是在Update函数中完成。

在协程函数中有类似的东西:

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;
}

这样做我没有遇到任何问题。只需启动协程,让它在while循环中永远运行。它不会冻结,因为它每1秒产生一次,也会产生每一帧。以下是完整的代码:

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);
    }
}