在Unity3D中截图,没有滞后

时间:2016-03-23 18:39:13

标签: c# android unity3d screen screenshot

我尝试了各种变体:http://wiki.unity3d.com/index.php/ScreenCapture 毕竟,简单的Application.Capturescreenshot(...)是最不了解的。

请告诉我,如何在没有任何滞后的情况下拍摄截图? Android上的很多游戏都具有thiis功能,因此并非不可能。

2 个答案:

答案 0 :(得分:6)

拍摄时滞后原因是指您尝试同时执行所有步骤时没有 等待每一步后。要解决此问题,您执行一个操作并等待多个帧,然后执行下一个操作,然后再次等待。如果您决定在游戏过程中保存图片,请使用线程保存图片。 EncodeToPNG()是另一个问题但我稍后会讨论另一个解决方案。

如果您想拍摄屏幕截图然后在游戏运行时立即显示,则下面的代码很好。 它将以正确的方式拍摄,然后花费大约1.5秒来保存文件。

 IEnumerator screenShotCoroutine()
{
    yield return new WaitForEndOfFrame();
    string path = Application.persistentDataPath + "/DrukaloScreenshot.png";

    Texture2D screenImage = new Texture2D(Screen.width, Screen.height);

    //Get Image from screen
    screenImage.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);

    //Wait for a long time
    for (int i = 0; i < 15; i++)
    {
        yield return null;
    }

    screenImage.Apply();

    //Wait for a long time
    for (int i = 0; i < 15; i++)
    {
        yield return null;
    }

    //Convert to png(Expensive)
    byte[] imageBytes = screenImage.EncodeToPNG();

    //Wait for a long time
    for (int i = 0; i < 15; i++)
    {
        yield return null;
    }

    //Create new thread then save image to file
    new System.Threading.Thread(() =>
    {
        System.Threading.Thread.Sleep(100);
        File.WriteAllBytes(path, imageBytes);
    }).Start();
}

如果你想拍照并且需要立即显示图片,你可以将图片保存为原始 Texture2D,然后如果您想稍后访问/加载/显示图片,您可以读取 文件,然后将其转换为 PNG 。这样做的原因是EncodeToPNG()非常昂贵,因此如果您不需要立即拍照,则无需将其转换为png。当你需要 png 时,你可以 。所以现在我们可以将它保存为&#34; .t2D &#34;然后加载它并将加载的图像转换为&#34; .png &#34;。

另存为Texture2D&#34; .t2D &#34;

IEnumerator screenShotCoroutine()
    {
        yield return new WaitForEndOfFrame();
        string path = Application.persistentDataPath + "/DrukaloScreenshot.t2D";

        Texture2D screenImage = new Texture2D(Screen.width, Screen.height);

        //Get Picture
        screenImage.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);

        //Wait for a long time
        for (int i = 0; i < 15; i++)
        {
            yield return null;
        }

        screenImage.Apply();

        //Wait for a long time
        for (int i = 0; i < 15; i++)
        {
            yield return null;
        }

        byte[] rawData = screenImage.GetRawTextureData();

        //Wait for a long time
        for (int i = 0; i < 15; i++)
        {
            yield return null;
        }

        //Create new thread then save image
        new System.Threading.Thread(() =>
        {
            System.Threading.Thread.Sleep(100);
            File.WriteAllBytes(path, rawData);
        }).Start();
    }

然后,当您确实需要图像时,请加载Texture2D&#34; .t2D &#34;然后将其转换为&#34; .png &#34;然后删除旧的&#34; .t2D &#34;。

IEnumerator screenShotCoroutine()
{
    string path = Application.persistentDataPath + "/DrukaloScreenshot.t2D";
    string newPath = Application.persistentDataPath + "/DrukaloScreenshot.png";

    Texture2D screenImage = new Texture2D(Screen.width, Screen.height);

    byte[] rawData = null;

    //Create new thread then Load image
    new System.Threading.Thread(() =>
    {
        System.Threading.Thread.Sleep(100);
        rawData = File.ReadAllBytes(path);
    }).Start();

    //Wait for a long time
    for (int i = 0; i < 9; i++)
    {
        yield return null;
    }

    //Put loaded bytes to Texture2D 
    screenImage.LoadRawTextureData(rawData);

    //Wait for a long time
    for (int i = 0; i < 9; i++)
    {
        yield return null;
    }

    screenImage.Apply();

    //Wait for a long time
    for (int i = 0; i < 9; i++)
    {
        yield return null;
    }

    //convert to png
    byte[] pngByte = screenImage.EncodeToPNG();

    //Wait for a long time
    for (int i = 0; i < 9; i++)
    {
        yield return null;
    }

    //Do whatever you want with the png file(display to screen or save as png)


    //Create new thread and Save the new png file, then Delete Old image(DrukaloScreenshot.t2D)
    new System.Threading.Thread(() =>
    {
        System.Threading.Thread.Sleep(100);
        File.WriteAllBytes(newPath, pngByte); //Save the new png file(DrukaloScreenshot.png)
        File.Delete(path); //Delete old file (DrukaloScreenshot.t2D)
    }).Start();
}

答案 1 :(得分:2)

Application.CaptureScreenshot()一般都很慢,更快的方法是使用Texture2D并使用ReadPixels()函数读取屏幕上的所有像素,而不是编码和保存纹理到了硬盘。

这是此方法的一个示例:

Texture2D screenShot = new Texture2D(Screen.width, Screen.height);
screenShot.ReadPixels(new Rect(0,0,Screen.width,Screen.height),0,0);
screenShot.Apply();
byte[] bytes = tex.EncodeToPNG();
Object.Destroy(tex);
File.WriteAllBytes(Application.dataPath + "/../myScreenShot.png", bytes);

要获得完整参考,您可以使用Unity脚本参考页面here