运行 Unity 在 Headless 模式下独立捕获屏幕截图
Run Unity standalone in Headless Mode whilst capturing screenshots
我需要创建一个以 Headless 模式运行的统一项目(使用 -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
后再截屏。
你说你想每秒截图并保存。这应该在协程中而不是在更新函数中完成。
协程函数中的类似内容:
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);
}
}
我需要创建一个以 Headless 模式运行的统一项目(使用 -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
后再截屏。
你说你想每秒截图并保存。这应该在协程中而不是在更新函数中完成。
协程函数中的类似内容:
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);
}
}