Skip to content

Instantly share code, notes, and snippets.

@krzys-h
Last active December 22, 2023 10:33
Show Gist options
  • Star 51 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
  • Save krzys-h/76c518be0516fb1e94c7efbdcd028830 to your computer and use it in GitHub Desktop.
Save krzys-h/76c518be0516fb1e94c7efbdcd028830 to your computer and use it in GitHub Desktop.
[Unity] Save RenderTexture to image file
using UnityEngine;
using UnityEditor;
public class SaveRenderTextureToFile {
[MenuItem("Assets/Save RenderTexture to file")]
public static void SaveRTToFile()
{
RenderTexture rt = Selection.activeObject as RenderTexture;
RenderTexture.active = rt;
Texture2D tex = new Texture2D(rt.width, rt.height, TextureFormat.RGB24, false);
tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
RenderTexture.active = null;
byte[] bytes;
bytes = tex.EncodeToPNG();
string path = AssetDatabase.GetAssetPath(rt) + ".png";
System.IO.File.WriteAllBytes(path, bytes);
AssetDatabase.ImportAsset(path);
Debug.Log("Saved to " + path);
}
[MenuItem("Assets/Save RenderTexture to file", true)]
public static bool SaveRTToFileValidation()
{
return Selection.activeObject is RenderTexture;
}
}
using UnityEngine;
using UnityEditor;
public class SaveScreenshotToFile {
[MenuItem("Custom/Render Camera to file")]
public static void RenderCameraToFile()
{
Camera camera = Selection.activeGameObject.GetComponent<Camera>();
RenderTexture rt = new RenderTexture(2560, 1440, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
RenderTexture oldRT = camera.targetTexture;
camera.targetTexture = rt;
camera.Render();
camera.targetTexture = oldRT;
RenderTexture.active = rt;
Texture2D tex = new Texture2D(rt.width, rt.height, TextureFormat.RGB24, false);
tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
RenderTexture.active = null;
byte[] bytes = tex.EncodeToPNG();
string path = "Assets/screenshot.png";
System.IO.File.WriteAllBytes(path, bytes);
AssetDatabase.ImportAsset(path);
Debug.Log("Saved to " + path);
}
[MenuItem("Custom/Render Camera to file", true)]
public static bool RenderCameraToFileValidation()
{
return Selection.activeGameObject != null && Selection.activeGameObject.GetComponent<Camera>() != null;
}
}
@mesrefoglu
Copy link

Works like a charm. Thanks a lot!

@kyuskoj
Copy link

kyuskoj commented Oct 9, 2021

Thanks. It helps me a lot.

@an36
Copy link

an36 commented Apr 23, 2022

Thank you!!

@mrchantey
Copy link

mrchantey commented Jun 17, 2022

Thank you!! Here's a remix that takes a shot directly from the camera

static void SaveRenderTexture(RenderTexture rt, string path)
{
	RenderTexture.active = rt;
	Texture2D tex = new Texture2D(rt.width, rt.height, TextureFormat.RGB24, false);
	tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
	RenderTexture.active = null;
	var bytes = tex.EncodeToPNG();
	System.IO.File.WriteAllBytes(path, bytes);
	AssetDatabase.ImportAsset(path);
	Debug.Log($"Saved texture: {rt.width}x{rt.height} - " + path);
}
[MenuItem("Assets/Take Screenshot", true)]
public static bool TakeScreenshotValidation() =>
	Selection.activeGameObject && Selection.activeGameObject.GetComponent<Camera>();
[MenuItem("Assets/Take Screenshot")]
public static void TakeScreenshot()
{
	var camera = Selection.activeGameObject.GetComponent<Camera>();
	var prev = camera.targetTexture;
	var rt = new RenderTexture(Screen.width, Screen.height, 16);
	camera.targetTexture = rt;
	camera.Render();
	SaveRenderTexture(rt, "Assets/screenshot.png");
	camera.targetTexture = prev;
	Object.DestroyImmediate(rt);
}

@krzys-h
Copy link
Author

krzys-h commented Jun 17, 2022

Since this gist seems useful to so many people, I added a variant which generates a screenshot from a camera, and works correctly with linear color space. This became necessary when we switched to using linear color space, since there was no way to create an sRGB render texture through the UI, and colors were coming out all weird in the screenshot otherwise (because most normal image files are expected to be in sRGB, not linear).

Also, in case you were wondering, simply changing Texture2D constructor parameter linear to true does not work, because ReadPixels does not perform the linear to sRGB conversion in this case, only actually rendering with a shader does.

Thanks @mrchantey for reminding me I have this ;)

@JBKacerovsky
Copy link

Thank you for publishing this. Very helpful!

@mateosss
Copy link

Remember to call Object.Destroy(tex) after you are done with the texture or it'll leak. See this example from unity docs

@jwvanderbeck
Copy link

jwvanderbeck commented Dec 9, 2022

This is very helpful, thanks. But is there a way to retain the alpha information that the RT has?
EDIT: Turns out it was a simple as changing the texture format to TextureFormat.RGBA32

@MrBelarus
Copy link

Thanks, helped a lot!

@Thaina
Copy link

Thaina commented Jul 30, 2023

Would like to suggest making this gist a general png saver

https://gist.github.com/Thaina/44730376d4ef58bb52496d851634a531

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment