问题
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