Unity:如何以~60fps的速度获得实时图像捕获?

时间:2017-05-25 14:28:33

标签: c# unity3d rendering real-time capture

我正在Unity中编写一个应用程序,需要每帧(约60fps)从摄像机捕获图像,并将结果数据发送到本地运行的另一个服务。

问题是,我知道在使用GetPixels()方法时,从相机捕获渲染数据会导致大量帧速率下降(as explained in this article)。文章解释了" GetPixels()阻止ReadPixels()完成"和#34; ReadPixels()在刷新GPU时阻塞#34;这就是为什么GPU和CPU必须同步,导致滞后。

我已经制作了一个带有脚本的示例项目,它只是将帧作为PNG输出到文件中,以复制我想要创建的程序的功能。我已尽力实现本文中描述的内容,即允许GPU渲染帧,然后在调用GetPixels()之前等待几帧,以免导致GPU和CPU强制同步。但是,我真的没有取得任何进展。该项目仍然以大约10-15fps的速度播放。

如何在Unity中实现每秒60帧的实时捕获?

using System;
using System.Collections;
using System.IO;
using UnityEngine;

namespace Assets
{
    public class MyClass: MonoBehaviour
    {
        private const float reportInterval = 0.5f;
        private int screenshotCount = 0;
        private const float maxElapsedSecond = 20;
        private string screenshotsDirectory = "UnityHeadlessRenderingScreenshots";
        public Camera camOV;
        public RenderTexture currentRT;
        private int frameCount = 0;
        private Texture2D resultantImage;

        public void Start()
        {
            camOV.forceIntoRenderTexture = true;
            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()
        {
            //Taking Screenshots
            frameCount += 1;
            if (frameCount == 1)
            {
                TakeScreenShot();
            }
            else if (frameCount == 3)
            {
                ReadPixelsOut("SS_"+screenshotCount+".png");
            }

            if (frameCount >= 3)
            {
                frameCount = 0;
            }
        }

        public void TakeScreenShot()
        {
            screenshotCount += 1;
            RenderTexture.active = camOV.targetTexture;
            camOV.Render();
            resultantImage = new Texture2D(camOV.targetTexture.width, camOV.targetTexture.height, TextureFormat.RGB24, false);
            resultantImage.ReadPixels(new Rect(0, 0, camOV.targetTexture.width, camOV.targetTexture.height), 0, 0);
            resultantImage.Apply();
        }

        private void ReadPixelsOut(string filename)
        {
            if (resultantImage != null)
            {
                resultantImage.GetPixels();
                RenderTexture.active = currentRT;

                byte[] bytes = resultantImage.EncodeToPNG();
                // save on disk
                var path = screenshotsDirectory + "/" + filename;
                File.WriteAllBytes(path, bytes);

                Destroy(resultantImage);
            }
        }
    }
}

文章暗示这是可能的,但我还没有设法让它发挥作用。

非常感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

我不确定OP是否还需要答案。但如果将来有人遇到同样的问题,让我分享一下我找到的东西。

https://github.com/unity3d-jp/FrameCapturer

这是一个专为在Unity编辑器中渲染动画视频而设计的插件。但它也可以独立工作。在我的情况下,我采取了一些部分,并使我的应用程序流动作Jpeg。我用30fps做到了,从未尝试过60fps