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

2024-05-02

我需要创建一个在无头模式下运行的统一项目(使用 -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);

        }
    }
}

提前谢谢了!


关于截屏,我给你的一个建议是等待WaitForEndOfFrame https://docs.unity3d.com/ScriptReference/WaitForEndOfFrame.html在截图之前。

你说你想每秒捕获屏幕截图并保存它。这应该在协程中完成,而不是在 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);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐