问题
I have tried each of variants: http://wiki.unity3d.com/index.php/ScreenCapture Afterall, simple Application.Capturescreenshot(...) is the least laggy.
Please, tell me, How I can take screenshots without ANY lags? Lots of games on Android has thiis feature, so it's not impossible.
回答1:
The cause of lag while taking picture is when you try to perform all steps at the same time without waiting after each step. To fix this, you perform one action and wait for many frames then perform the next action then wait again. And if you decide to save the picture during game-play, use Thread to save the picture. EncodeToPNG()
is another problem but I will talk about another solution for it later on.
The code below is good if you want to take screen shot then display it right away while game is running. It will take picture right way then take about 1.5 seconds to save the file.
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();
}
If you want to take the picture and you are not required to display the image right away, you can save the picture as raw Texture2D
, then when you want to access/load/display the picture later on, you can read it from file then convert it to PNG later on. The reason for this is that EncodeToPNG()
is very expensive so if you don't need the picture right away, there is no need to convert it to png. You can do that only when you actually need it as png. So now we can just save it as ".t2D" then load it after and convert the loaded image to ".png".
Save as Texture2D ".t2D"
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();
}
Then when you actually need the image, load Texture2D ".t2D" and then covert it to ".png" followed by deleting the old ".t2D".
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();
}
回答2:
Application.CaptureScreenshot()
is slow in general, a faster way is to use a Texture2D
and read all the pixels on the screen on it using ReadPixels()
function than you can encode and save the texture to the hard drive.
This is an example of this method:
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);
For a full reference you can use Unity scripting reference page here.
来源:https://stackoverflow.com/questions/36186209/take-screenshot-in-unity3d-with-no-lags