本文介绍了在无屏模式下独立运行Unity并捕获屏幕截图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

我知道在无头模式下,您需要强制调用Camera.Render()才能渲染任何内容.

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

        }
    }
}

非常感谢!

推荐答案

我会为您提供有关截图的一个建议是等待 WaitForEndOfFrame ,然后再抓屏.

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

您说过要每秒捕获一次屏幕截图并将其保存.这应该在协程中完成,而不是在Update函数中完成.

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

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

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

这篇关于在无屏模式下独立运行Unity并捕获屏幕截图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-29 14:19