For my equally ridiculous follow-up to Brick Buddies, I need to save a screenshot both as a texture and as a file in Unity3D. Although the game I’m currently writing has screenshots as an integral gameplay element, it’s still useful to integrate screenshots into any Unity3D project. Using Prime31’s Social Networking plug-in, it’s possible to Tweet pictures or post screens to user’s Facebook galleries. Having a screenshot capture feature can boost your viral reach. Especially if you design your application in such a way that people want toshare screenshots. In Unity3D, there are a number of ways to do this.
Application.CaptureScreenshot
CaptureScreenshot is a method in the Application class that does exactly what it says; it saves the screenshot as a PNG file. On iOS devices, this screenshot will be put in the Documents folder. On other platforms you can specify an absolute path to put the file anywhere.
What the documentation doesn’t tell you is CaptureScreenshot is asynchronous. This is because capturing and saving the screen can take awhile. The API call itself isn’t a coroutine, so there’s no easy way to monitor its progress. One hack is to write your own method which checks for the existence of the screenshot file. Once the screenshot has completed saving, the file will be there.
Also note that it’s good practice to put CaptureScreenshot calls in the LateUpdate method. This way you capture the contents of the frame as it will look at the end of that update. If you have made any objects active or inactive during that frame, the results of those operations will be seen in LateUpdate.
RenderTexture
One convoluted way to take a screenshot is to use the RenderTexture feature in Unity Pro. You can create a RenderTexture object and tell any camera to write to it. You can then access the color buffer of the RenderTexture if you want to write out the pixels to a PNG.
CaptureScreenshot was just way too slow for my needs (I needed immediate access to the frame buffer) so I started writing a RenderTexture solution, until I found an easier way. If you want to check out this technique, I suggest this example.
Texture2D.ReadPixels
ReadPixels will read the pixel data from a specified rectangle on the screen and copy it to the source texture. It’s fairly fast and works with a few lines of code. Much like CaptureScreenshot, it’s a good idea to queue up the action somehow and then actually call ReadPixels in LateUpdate. Works like a charm:
Texture2D tex = new Texture2D(Screen.width, Screen.height);
tex.ReadPixels(new Rect(0,0,Screen.width,Screen.height),0,0);
tex.Apply();
ReadPixels still introduces some delay, so in the end I might try to see if RenderTexture is faster. If you are using the screenshots as a real-time texture effect, then RenderTexture is your best bet.