2017-05-19 38 views
1

我需要創建一個以無頭模式(使用-batchmode命令)運行的統一項目,但它必須捕獲截圖每隔一秒鐘寫出一個文件。在無頭模式下運行Unity獨立,同時捕捉屏幕截圖

我明白,在無頭模式下,您需要強制調用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

您遺漏了一些東西。什麼是'currentRT'?它是如何初始化的? – Programmer

+0

@程序員對不起,我已將完整的腳本添加到問題中。它們通過編輯器分配(拖放到腳本中的公共變量) –

+0

好的。我現在看到更新。你是通過編輯器還是構建來測試它?你究竟在傳遞什麼命令? – Programmer

回答

2

我會給你一個關於截圖的建議是在截圖前等待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; 
} 

我沒有做它該遇到的任何問題。只需啓動協程,讓它在一段時間內永遠運行。它不會凍結,因爲它每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); 
    } 
} 
+0

非常感謝您的回答。不幸的是,它似乎(正如我們在我們的項目中發現的那樣)執行沒有通過yield return waitForFrame;當處於無頭模式時 –

+0

您是否按照原樣複製此代碼或者是否修改了它?你可以在不修改任何部分的情況下運行它嗎? – Programmer

+0

我之所以這樣說是因爲當你沒有正確啓動協程時,通常你描述的行爲。它應該是'StartCoroutine(TakeScreenShot());'不是'TakeScreenShot()'。無論如何,確保代碼沒有被修改。 – Programmer